const ExcelJS = require("exceljs"); 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 { setResponse, setResponsePaging, checkValidate, } = require("../helpers/utils"); const { insertSparepartSchema, updateSparepartSchema, } = require("../validate/sparepart.schema"); class SparepartController { static async getAll(req, res) { const queryParams = req.query; const results = await SparepartService.getAllSparepart(queryParams); const response = await setResponsePaging( queryParams, results, "Sparepart found" ); res.status(response.statusCode).json(response); } static async getById(req, res) { const { id } = req.params; const results = await SparepartService.getSparepartById(id); const response = await setResponse(results, "Sparepart found"); res.status(response.statusCode).json(response); } static async create(req, res) { const { error, value } = await checkValidate(insertSparepartSchema, req); if (error) { return res.status(400).json(setResponse(error, "Validation failed", 400)); } try { if (req.file) { const upload = await imagekit.upload({ file: req.file.buffer, fileName: req.file.originalname, folder: "/sparepart", }); value.sparepart_foto = upload.url; } value.userId = req.user.user_id; const results = await SparepartService.createSparepart(value); return res .status(201) .json(setResponse(results, "Sparepart created successfully")); } catch (err) { return res .status(err.statusCode || 500) .json(setResponse([], err.message, err.statusCode || 500)); } } static async update(req, res) { const { id } = req.params; const { error, value } = await checkValidate(updateSparepartSchema, req); if (error) { return res.status(400).json(setResponse(error, "Validation failed", 400)); } try { if (req.file) { const upload = await imagekit.upload({ file: req.file.buffer, fileName: req.file.originalname, folder: "/sparepart", }); value.sparepart_foto = upload.url; } value.userId = req.user.user_id; const results = await SparepartService.updateSparepart(id, value); return res .status(200) .json(setResponse(results, "Sparepart updated successfully")); } catch (err) { return res .status(err.statusCode || 500) .json(setResponse([], err.message, err.statusCode || 500)); } } static async exportExcel(req, res) { try { const queryParams = req.query || {}; queryParams.limit = null; const results = await SparepartService.getAllSparepart(queryParams); const workbook = new ExcelJS.Workbook(); const worksheet = workbook.addWorksheet("Sparepart Data"); worksheet.columns = [ { header: "Name Sparepart", key: "sparepart_name", width: 30 }, { header: "Code Sparepart", key: "sparepart_code", width: 20 }, { header: "QTY Sparepart", key: "sparepart_qty", width: 15 }, { header: "Merk", key: "sparepart_merk", width: 20 }, { header: "Model", key: "sparepart_model", width: 20 }, { header: "Unit", key: "sparepart_unit", width: 10 }, { header: "Stock", key: "sparepart_stok", width: 10 }, { header: "Foto", key: "sparepart_foto", width: 25 }, { header: "Item Type", key: "sparepart_item_type", width: 25 }, { header: "Dibuat Pada", key: "created_at", width: 20 }, ]; worksheet.addRows( results.data.map((item) => ({ ...item, sparepart_foto: "", })) ); for (let i = 0; i < results.data.length; i++) { const item = results.data[i]; const rowNumber = i + 2; if (!item.sparepart_foto) continue; let imageUrl = item.sparepart_foto; if (!imageUrl.startsWith("https")) continue; let ext = path.extname(imageUrl).toLowerCase().replace(".", ""); if (!ext) ext = "jpg"; const supported = ["jpg", "jpeg", "png"]; if (!supported.includes(ext)) { ext = "png"; } 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) => { cell.font = { bold: true }; cell.alignment = { horizontal: "center" }; }); const buffer = await workbook.xlsx.writeBuffer(); res.setHeader( "Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ); res.setHeader( "Content-Disposition", "attachment; filename=sparepart_data.xlsx" ); return res.send(buffer); } catch (error) { 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 }); } } static async delete(req, res) { const { id } = req.params; const results = await SparepartService.deleteSparepart( id, req.user.user_id ); const response = await setResponse( results, "Sparepart deleted successfully" ); res.status(response.statusCode).json(response); } } module.exports = SparepartController;