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.
171 lines
4.8 KiB
TypeScript
171 lines
4.8 KiB
TypeScript
import "server-only";
|
|
|
|
import { and, asc, count, eq, like, or } from "drizzle-orm";
|
|
import { amigoDb } from "@/db/amigo";
|
|
import { barang, kedalaman_produk, strip } from "@/db/amigo/schema";
|
|
import { PER_PAGE } from "@/lib/pagination";
|
|
import { escapeLike } from "@/lib/utils";
|
|
|
|
export type SubGroupProduct = {
|
|
id: number;
|
|
kodeKedProduk: string;
|
|
kedProduk: string;
|
|
kodeStrip: string | null;
|
|
namaStrip: string | null;
|
|
};
|
|
|
|
export type SubGroupProductPage = {
|
|
rows: SubGroupProduct[];
|
|
hasNext: boolean;
|
|
};
|
|
|
|
// Identitas sub group = pasangan (kodeStrip, kodeKedProduk); `id` hanya primary key teknis.
|
|
export type SubGroupProductInput = {
|
|
kodeKedProduk: string;
|
|
kedProduk: string;
|
|
kodeStrip: string;
|
|
};
|
|
|
|
// Kode tidak ikut diubah: barang menunjuk sub group lewat pasangan kode, jadi mengganti kode
|
|
// membuat barang yatim. PHP lama juga hanya mengubah nama (`ajaxdlmpdk.php`).
|
|
export type SubGroupProductUpdate = Pick<SubGroupProductInput, "kedProduk">;
|
|
|
|
// Dilempar untuk isian yang ditolak aturan bisnis (kode dobel, group tidak ada), supaya action
|
|
// bisa membedakannya dari error DB lain yang perlu di-log.
|
|
export class SubGroupProductDitolakError extends Error {}
|
|
|
|
async function findSubGroupProduct(
|
|
kodeStrip: string,
|
|
kodeKedProduk: string,
|
|
): Promise<{ id: number } | undefined> {
|
|
const [row] = await amigoDb
|
|
.select({ id: kedalaman_produk.id })
|
|
.from(kedalaman_produk)
|
|
.where(
|
|
and(
|
|
eq(kedalaman_produk.kode_strip, kodeStrip),
|
|
eq(kedalaman_produk.kode_ked_produk, kodeKedProduk),
|
|
),
|
|
)
|
|
.limit(1);
|
|
|
|
return row;
|
|
}
|
|
|
|
async function isGroupProductExist(kodeStrip: string): Promise<boolean> {
|
|
const [row] = await amigoDb
|
|
.select({ kdStrip: strip.kd_strip })
|
|
.from(strip)
|
|
.where(eq(strip.kd_strip, kodeStrip))
|
|
.limit(1);
|
|
|
|
return row !== undefined;
|
|
}
|
|
|
|
export async function insertSubGroupProduct(
|
|
input: SubGroupProductInput,
|
|
): Promise<number> {
|
|
if (!(await isGroupProductExist(input.kodeStrip))) {
|
|
throw new SubGroupProductDitolakError(
|
|
`Group product ${input.kodeStrip} tidak ditemukan, pilih ulang group product`,
|
|
);
|
|
}
|
|
|
|
// Tidak ada unique index di DB (MyISAM), jadi cek dobel manual sebelum insert.
|
|
if (await findSubGroupProduct(input.kodeStrip, input.kodeKedProduk)) {
|
|
throw new SubGroupProductDitolakError(
|
|
`Kode ${input.kodeKedProduk} sudah dipakai di group product ${input.kodeStrip}`,
|
|
);
|
|
}
|
|
|
|
const [res] = await amigoDb.insert(kedalaman_produk).values({
|
|
kode_ked_produk: input.kodeKedProduk,
|
|
ked_produk: input.kedProduk,
|
|
kode_strip: input.kodeStrip,
|
|
});
|
|
|
|
return res.insertId;
|
|
}
|
|
|
|
export async function updateSubGroupProduct(
|
|
id: number,
|
|
input: SubGroupProductUpdate,
|
|
): Promise<boolean> {
|
|
const [res] = await amigoDb
|
|
.update(kedalaman_produk)
|
|
.set({ ked_produk: input.kedProduk })
|
|
.where(eq(kedalaman_produk.id, id));
|
|
|
|
return res.affectedRows > 0;
|
|
}
|
|
|
|
// `barang` menunjuk sub group lewat pasangan (kode_strip, ked_produk), bukan lewat id.
|
|
export async function countPemakaianSubGroupProduct(
|
|
id: number,
|
|
): Promise<number> {
|
|
const [row] = await amigoDb
|
|
.select({ total: count() })
|
|
.from(barang)
|
|
.innerJoin(
|
|
kedalaman_produk,
|
|
and(
|
|
eq(barang.kode_strip, kedalaman_produk.kode_strip),
|
|
eq(barang.ked_produk, kedalaman_produk.kode_ked_produk),
|
|
),
|
|
)
|
|
.where(eq(kedalaman_produk.id, id));
|
|
|
|
return row?.total ?? 0;
|
|
}
|
|
|
|
export async function deleteSubGroupProduct(id: number): Promise<boolean> {
|
|
const [res] = await amigoDb
|
|
.delete(kedalaman_produk)
|
|
.where(eq(kedalaman_produk.id, id));
|
|
|
|
return res.affectedRows > 0;
|
|
}
|
|
|
|
export async function listSubGroupProduct(
|
|
search?: string,
|
|
page = 1,
|
|
): Promise<SubGroupProductPage> {
|
|
const q = search?.trim();
|
|
const pattern = q ? `%${escapeLike(q)}%` : "";
|
|
|
|
const rows = await amigoDb
|
|
.select({
|
|
id: kedalaman_produk.id,
|
|
kodeKedProduk: kedalaman_produk.kode_ked_produk,
|
|
kedProduk: kedalaman_produk.ked_produk,
|
|
kodeStrip: kedalaman_produk.kode_strip,
|
|
namaStrip: strip.nama_strip,
|
|
})
|
|
.from(kedalaman_produk)
|
|
// leftJoin: ada data lama yang menunjuk kode group yang sudah tidak ada.
|
|
.leftJoin(strip, eq(kedalaman_produk.kode_strip, strip.kd_strip))
|
|
.where(
|
|
q
|
|
? or(
|
|
like(kedalaman_produk.ked_produk, pattern),
|
|
like(kedalaman_produk.kode_strip, pattern),
|
|
like(kedalaman_produk.kode_ked_produk, pattern),
|
|
like(strip.nama_strip, pattern),
|
|
)
|
|
: undefined,
|
|
)
|
|
// id sebagai pengurut terakhir: urutan antar-query tetap stabil di batas halaman.
|
|
.orderBy(
|
|
asc(kedalaman_produk.kode_strip),
|
|
asc(kedalaman_produk.kode_ked_produk),
|
|
asc(kedalaman_produk.id),
|
|
)
|
|
.limit(PER_PAGE + 1)
|
|
.offset((page - 1) * PER_PAGE);
|
|
|
|
return {
|
|
rows: rows.slice(0, PER_PAGE),
|
|
hasNext: rows.length > PER_PAGE,
|
|
};
|
|
}
|