add: import , repair: change save local storage to imagekit

This commit is contained in:
2025-12-02 10:44:07 +07:00
parent 920b24bfd2
commit 28e99c2a0d
3 changed files with 202 additions and 57 deletions

View File

@@ -1,8 +1,15 @@
const ExcelJS = require("exceljs"); const ExcelJS = require("exceljs");
const fs = require("fs");
const path = require("path"); const path = require("path");
const ImageKit = require("imagekit");
const imagekit = new ImageKit({
publicKey: process.env.IMAGEKIT_PUBLIC_KEY,
privateKey: process.env.IMAGEKIT_PRIVATE_KEY,
urlEndpoint: process.env.IMAGEKIT_URL_ENDPOINT,
});
const SparepartService = require("../services/sparepart.service"); const SparepartService = require("../services/sparepart.service");
const { const {
setResponse, setResponse,
setResponsePaging, setResponsePaging,
@@ -38,25 +45,28 @@ class SparepartController {
if (error) { if (error) {
return res.status(400).json(setResponse(error, "Validation failed", 400)); return res.status(400).json(setResponse(error, "Validation failed", 400));
} }
try { try {
if (req.file) { if (req.file) {
const file = req.file; const upload = await imagekit.upload({
const ext = require("path").extname(file.originalname).toLowerCase(); file: req.file.buffer,
const typeDoc = ext === ".pdf" ? "PDF" : "IMAGE"; fileName: req.file.originalname,
const folder = typeDoc === "PDF" ? "pdf" : "images"; folder: "/sparepart",
const pathDocument = `${folder}/${file.filename}`; });
value.sparepart_foto = pathDocument;
value.sparepart_foto = upload.url;
} }
value.userId = req.user.user_id; value.userId = req.user.user_id;
const results = await SparepartService.createSparepart(value); const results = await SparepartService.createSparepart(value);
const response = await setResponse( return res
results, .status(201)
"Sparepart created successfully" .json(setResponse(results, "Sparepart created successfully"));
);
return res.status(response.statusCode).json(response);
} catch (err) { } catch (err) {
const response = setResponse([], err.message, err.statusCode || 500); return res
res.status(response.statusCode).json(response); .status(err.statusCode || 500)
.json(setResponse([], err.message, err.statusCode || 500));
} }
} }
@@ -66,25 +76,28 @@ class SparepartController {
if (error) { if (error) {
return res.status(400).json(setResponse(error, "Validation failed", 400)); return res.status(400).json(setResponse(error, "Validation failed", 400));
} }
try { try {
if (req.file) { if (req.file) {
const file = req.file; const upload = await imagekit.upload({
const ext = require("path").extname(file.originalname).toLowerCase(); file: req.file.buffer,
const typeDoc = ext === ".pdf" ? "PDF" : "IMAGE"; fileName: req.file.originalname,
const folder = typeDoc === "PDF" ? "pdf" : "images"; folder: "/sparepart",
const pathDocument = `${folder}/${file.filename}`; });
value.sparepart_foto = pathDocument;
value.sparepart_foto = upload.url;
} }
value.userId = req.user.user_id; value.userId = req.user.user_id;
const results = await SparepartService.updateSparepart(id, value); const results = await SparepartService.updateSparepart(id, value);
const response = await setResponse( return res
results, .status(200)
"Sparepart updated successfully" .json(setResponse(results, "Sparepart updated successfully"));
);
res.status(response.statusCode).json(response);
} catch (err) { } catch (err) {
const response = setResponse([], err.message, err.statusCode || 500); return res
res.status(response.statusCode).json(response); .status(err.statusCode || 500)
.json(setResponse([], err.message, err.statusCode || 500));
} }
} }
@@ -113,16 +126,8 @@ class SparepartController {
worksheet.addRows( worksheet.addRows(
results.data.map((item) => ({ results.data.map((item) => ({
sparepart_name: item.sparepart_name, ...item,
sparepart_code: item.sparepart_code,
sparepart_qty: item.sparepart_qty,
sparepart_merk: item.sparepart_merk,
sparepart_model: item.sparepart_model,
sparepart_unit: item.sparepart_unit,
sparepart_stok: item.sparepart_stok,
sparepart_foto: "", sparepart_foto: "",
sparepart_item_type: item.sparepart_item_type,
created_at: item.created_at,
})) }))
); );
@@ -132,27 +137,38 @@ class SparepartController {
if (!item.sparepart_foto) continue; if (!item.sparepart_foto) continue;
let foto = item.sparepart_foto.trim(); let imageUrl = item.sparepart_foto;
foto = foto.replace(/^images\//, ""); if (!imageUrl.startsWith("https")) continue;
const fullPath = path.resolve(process.cwd(), "uploads", "images", foto); let ext = path.extname(imageUrl).toLowerCase().replace(".", "");
if (fs.existsSync(fullPath)) { if (!ext) ext = "jpg";
const ext = fullPath.split(".").pop().toLowerCase();
const imageId = workbook.addImage({ const supported = ["jpg", "jpeg", "png"];
filename: fullPath, if (!supported.includes(ext)) {
extension: ext, ext = "png";
});
worksheet.addImage(imageId, {
tl: { col: 7, row: rowNumber - 1 },
ext: { width: 80, height: 80 },
});
worksheet.getRow(rowNumber).height = 70;
} }
let buffer;
try {
const resp = await fetch(imageUrl);
buffer = Buffer.from(await resp.arrayBuffer());
} catch (e) {
continue;
}
const imageId = workbook.addImage({
buffer,
extension: ext === "jpg" ? "jpeg" : ext,
});
worksheet.addImage(imageId, {
tl: { col: 7, row: rowNumber - 1 },
ext: { width: 80, height: 80 },
});
worksheet.getRow(rowNumber).height = 70;
} }
worksheet.getRow(1).eachCell((cell) => { worksheet.getRow(1).eachCell((cell) => {
@@ -173,10 +189,124 @@ class SparepartController {
return res.send(buffer); return res.send(buffer);
} catch (error) { } catch (error) {
console.log("Export Excel Error:", error); return res.status(500).json({ message: error.message });
return res.status(500).json({ }
message: error.message, }
static async importExcel(req, res) {
try {
const workbook = new ExcelJS.Workbook();
await workbook.xlsx.load(req.file.buffer);
const worksheet = workbook.getWorksheet(1);
const images = worksheet.getImages();
const imageMap = {};
images.forEach((imgObj) => {
const imageId = imgObj.imageId;
const range = imgObj.range;
const row = range.tl.nativeRow + 1;
const image = workbook.getImage(imageId);
imageMap[row] = image;
}); });
const spareparts = [];
worksheet.eachRow({ includeEmpty: false }, (row, rowNumber) => {
if (rowNumber === 1) return;
const [
sparepart_name,
sparepart_code,
sparepart_description,
sparepart_qty_excel,
sparepart_merk,
sparepart_model,
sparepart_unit,
sparepart_stok_excel,
sparepart_foto_excel,
sparepart_item_type,
] = row.values.slice(1);
if (!sparepart_name) return;
if (!sparepart_code) {
return;
}
spareparts.push({
sparepart_name: sparepart_name || "",
sparepart_code: sparepart_code || "",
sparepart_description: sparepart_description || "",
sparepart_qty: Number(sparepart_qty_excel) || 0,
sparepart_merk: sparepart_merk || "",
sparepart_model: sparepart_model || "",
sparepart_unit: sparepart_unit || "",
sparepart_stok: sparepart_stok_excel || "",
sparepart_foto: sparepart_foto_excel || "",
sparepart_item_type: sparepart_item_type || "",
rowNumber,
});
});
if (spareparts.length === 0) {
return res
.status(400)
.json(setResponse([], "Tidak ada data valid untuk diimport", 400));
}
const results = [];
for (const data of spareparts) {
let uploadedUrl = "";
try {
const image = imageMap[data.rowNumber];
if (image) {
const fileName = `sparepart_${Date.now()}_${
data.sparepart_code
}.jpg`;
const uploadResult = await imagekit.upload({
file: image.buffer,
fileName: fileName,
folder: "/sparepart",
});
uploadedUrl = uploadResult.url;
}
} catch (err) {
err;
}
data.sparepart_foto = uploadedUrl || "";
const { rowNumber, ...dbData } = data;
const created = await SparepartService.createSparepart(dbData);
if (created && created[0]) {
results.push({
sparepart_id: created[0].sparepart_id,
sparepart_name: created[0].sparepart_name,
sparepart_code: created[0].sparepart_code,
sparepart_description: created[0].sparepart_description,
sparepart_qty: created[0].sparepart_qty,
sparepart_merk: created[0].sparepart_merk,
sparepart_model: created[0].sparepart_model,
sparepart_unit: created[0].sparepart_unit,
sparepart_stok: created[0].sparepart_stok,
sparepart_foto: created[0].sparepart_foto,
sparepart_item_type: created[0].sparepart_item_type,
});
}
}
return res.json(
setResponse(results, `${results.length} Sparepart berhasil diimport`)
);
} catch (error) {
return res.status(500).json({ message: error.message });
} }
} }
@@ -193,4 +323,5 @@ class SparepartController {
res.status(response.statusCode).json(response); res.status(response.statusCode).json(response);
} }
} }
module.exports = SparepartController; module.exports = SparepartController;

5
middleware/upload.js Normal file
View File

@@ -0,0 +1,5 @@
const multer = require("multer");
const storage = multer.memoryStorage();
module.exports = multer({ storage });

View File

@@ -2,7 +2,8 @@ const express = require("express");
const SparepartController = require("../controllers/sparepart.controller"); const SparepartController = require("../controllers/sparepart.controller");
const verifyToken = require("../middleware/verifyToken"); const verifyToken = require("../middleware/verifyToken");
const verifyAccess = require("../middleware/verifyAccess"); const verifyAccess = require("../middleware/verifyAccess");
const upload = require("../middleware/uploads"); const upload = require("../middleware/upload");
const router = express.Router(); const router = express.Router();
router.get( router.get(
@@ -11,6 +12,14 @@ router.get(
SparepartController.exportExcel SparepartController.exportExcel
); );
router.post(
"/import",
verifyToken.verifyAccessToken,
verifyAccess(),
upload.single("file"),
SparepartController.importExcel
);
router router
.route("/") .route("/")
.get(verifyToken.verifyAccessToken, SparepartController.getAll) .get(verifyToken.verifyAccessToken, SparepartController.getAll)
@@ -36,4 +45,4 @@ router
SparepartController.delete SparepartController.delete
); );
module.exports = router; module.exports = router;