diff --git a/db/brand_sparepart.db.js b/db/brand_sparepart.db.js index 850879d..3cc37f1 100644 --- a/db/brand_sparepart.db.js +++ b/db/brand_sparepart.db.js @@ -1,9 +1,128 @@ const pool = require("../config"); -// Get spareparts by brand_id -const getSparepartsByBrandIdDb = async (brandId) => { +// Get spareparts by error_code_id +const getSparepartsByErrorCodeIdDb = async (errorCodeId) => { const queryText = ` SELECT + s.sparepart_id, + s.sparepart_name, + s.sparepart_code, + s.sparepart_description, + s.sparepart_model, + s.sparepart_foto, + s.sparepart_item_type, + s.sparepart_qty, + s.sparepart_unit, + s.sparepart_merk, + s.sparepart_stok, + bs.created_at, + bs.created_by + FROM brand_spareparts bs + JOIN m_sparepart s ON bs.sparepart_id = s.sparepart_id + WHERE bs.error_code_id = $1 + AND s.deleted_at IS NULL + ORDER BY s.sparepart_name + `; + const result = await pool.query(queryText, [errorCodeId]); + return result.recordset; +}; + +// Get error codes by sparepart_id +const getErrorCodesBySparepartIdDb = async (sparepartId) => { + const queryText = ` + SELECT + ec.error_code_id, + ec.error_code, + ec.error_code_name, + ec.error_code_description, + ec.error_code_color, + ec.path_icon, + ec.is_active, + ec.created_at, + ec.updated_at + FROM brand_spareparts bs + JOIN m_error_codes ec ON bs.error_code_id = ec.error_code_id + WHERE bs.sparepart_id = $1 + AND ec.deleted_at IS NULL + ORDER BY ec.error_code + `; + const result = await pool.query(queryText, [sparepartId]); + return result.recordset; +}; + +// Insert error_code-spareparts relationship +const insertErrorCodeSparepartDb = async (errorCodeId, sparepartId, createdBy) => { + const queryText = ` + INSERT INTO brand_spareparts (error_code_id, sparepart_id, created_by, created_at) + VALUES ($1, $2, $3, CURRENT_TIMESTAMP) + `; + const result = await pool.query(queryText, [errorCodeId, sparepartId, createdBy]); + return result.recordset; +}; + +// Insert multiple error_code-spareparts relationships +const insertMultipleErrorCodeSparepartsDb = async (errorCodeId, sparepartIds, createdBy) => { + if (!sparepartIds || sparepartIds.length === 0) return []; + + const values = sparepartIds.map((_, index) => `($1, $${index + 2}, $${sparepartIds.length + 2}, CURRENT_TIMESTAMP)`).join(', '); + const queryText = ` + INSERT INTO brand_spareparts (error_code_id, sparepart_id, created_by, created_at) + VALUES ${values} + `; + const params = [errorCodeId, ...sparepartIds, createdBy]; + const result = await pool.query(queryText, params); + return result.recordset; +}; + +// Delete specific error_code-sparepart relationship +const deleteErrorCodeSparepartDb = async (errorCodeId, sparepartId) => { + const queryText = ` + DELETE FROM brand_spareparts + WHERE error_code_id = $1 AND sparepart_id = $2 + `; + const result = await pool.query(queryText, [errorCodeId, sparepartId]); + return result.rowsAffected > 0; +}; + +// Delete all spareparts for an error_code +const deleteAllErrorCodeSparepartsDb = async (errorCodeId) => { + const queryText = ` + DELETE FROM brand_spareparts + WHERE error_code_id = $1 + `; + const result = await pool.query(queryText, [errorCodeId]); + return result.rowsAffected > 0; +}; + +// Update error_code-spareparts (replace all) +const updateErrorCodeSparepartsDb = async (errorCodeId, sparepartIds, updatedBy) => { + // Delete existing relationships + await deleteAllErrorCodeSparepartsDb(errorCodeId); + + // Insert new relationships + if (sparepartIds && sparepartIds.length > 0) { + return await insertMultipleErrorCodeSparepartsDb(errorCodeId, sparepartIds, updatedBy); + } + + return true; +}; + +// Check if error_code-sparepart relationship exists +const checkErrorCodeSparepartExistsDb = async (errorCodeId, sparepartId) => { + const queryText = ` + SELECT 1 + FROM brand_spareparts + WHERE error_code_id = $1 AND sparepart_id = $2 + `; + const result = await pool.query(queryText, [errorCodeId, sparepartId]); + return result.recordset.length > 0; +}; + +// Legacy functions for backward compatibility (deprecated) +// Get spareparts by brand_id (now using error_code_id mapping via error codes) +const getSparepartsByBrandIdDb = async (brandId) => { + const queryText = ` + SELECT DISTINCT s.sparepart_id, s.sparepart_name, s.sparepart_code, @@ -19,18 +138,20 @@ const getSparepartsByBrandIdDb = async (brandId) => { s.updated_at FROM brand_spareparts bs JOIN m_sparepart s ON bs.sparepart_id = s.sparepart_id - WHERE bs.brand_id = $1 + JOIN m_error_codes ec ON bs.error_code_id = ec.error_code_id + WHERE ec.brand_id = $1 AND s.deleted_at IS NULL + AND ec.deleted_at IS NULL ORDER BY s.sparepart_name `; const result = await pool.query(queryText, [brandId]); return result.recordset; }; -// Get brands by sparepart_id +// Get brands by sparepart_id (now using error_code_id mapping) const getBrandsBySparepartIdDb = async (sparepartId) => { const queryText = ` - SELECT + SELECT DISTINCT b.brand_id, b.brand_name, b.brand_type, @@ -41,8 +162,12 @@ const getBrandsBySparepartIdDb = async (sparepartId) => { b.created_at, b.updated_at FROM brand_spareparts bs - JOIN m_brands b ON bs.brand_id = b.brand_id + JOIN m_sparepart s ON bs.sparepart_id = s.sparepart_id + JOIN m_error_codes ec ON bs.error_code_id = ec.error_code_id + JOIN m_brands b ON ec.brand_id = b.brand_id WHERE bs.sparepart_id = $1 + AND s.deleted_at IS NULL + AND ec.deleted_at IS NULL AND b.deleted_at IS NULL ORDER BY b.brand_name `; @@ -50,81 +175,16 @@ const getBrandsBySparepartIdDb = async (sparepartId) => { return result.recordset; }; -// Insert brand-spareparts relationship -const insertBrandSparepartDb = async (brandId, sparepartId, createdBy) => { - const queryText = ` - INSERT INTO brand_spareparts (brand_id, sparepart_id, created_by, created_at) - VALUES ($1, $2, $3, CURRENT_TIMESTAMP) - `; - const result = await pool.query(queryText, [brandId, sparepartId, createdBy]); - return result.recordset; -}; - -// Insert multiple brand-spareparts relationships -const insertMultipleBrandSparepartsDb = async (brandId, sparepartIds, createdBy) => { - if (!sparepartIds || sparepartIds.length === 0) return []; - - const values = sparepartIds.map((_, index) => `($1, $${index + 2}, $${sparepartIds.length + 2}, CURRENT_TIMESTAMP)`).join(', '); - const queryText = ` - INSERT INTO brand_spareparts (brand_id, sparepart_id, created_by, created_at) - VALUES ${values} - `; - const params = [brandId, ...sparepartIds, createdBy]; - const result = await pool.query(queryText, params); - return result.recordset; -}; - -// Delete specific brand-sparepart relationship -const deleteBrandSparepartDb = async (brandId, sparepartId) => { - const queryText = ` - DELETE FROM brand_spareparts - WHERE brand_id = $1 AND sparepart_id = $2 - `; - const result = await pool.query(queryText, [brandId, sparepartId]); - return result.rowsAffected > 0; -}; - -// Delete all spareparts for a brand -const deleteAllBrandSparepartsDb = async (brandId) => { - const queryText = ` - DELETE FROM brand_spareparts - WHERE brand_id = $1 - `; - const result = await pool.query(queryText, [brandId]); - return result.rowsAffected > 0; -}; - -// Update brand-spareparts (replace all) -const updateBrandSparepartsDb = async (brandId, sparepartIds, updatedBy) => { - // Delete existing relationships - await deleteAllBrandSparepartsDb(brandId); - - // Insert new relationships - if (sparepartIds && sparepartIds.length > 0) { - return await insertMultipleBrandSparepartsDb(brandId, sparepartIds, updatedBy); - } - - return true; -}; - -// Check if brand-sparepart relationship exists -const checkBrandSparepartExistsDb = async (brandId, sparepartId) => { - const queryText = ` - SELECT 1 - FROM brand_spareparts - WHERE brand_id = $1 AND sparepart_id = $2 - `; - const result = await pool.query(queryText, [brandId, sparepartId]); - return result.recordset.length > 0; -}; +// Deprecated functions removed - table structure changed to use error_code_id instead of brand_id module.exports = { - getSparepartsByBrandIdDb, - getBrandsBySparepartIdDb, - insertBrandSparepartDb, - insertMultipleBrandSparepartsDb, - deleteBrandSparepartDb, - deleteAllBrandSparepartsDb, - updateBrandSparepartsDb, - checkBrandSparepartExistsDb, + // New functions using error_code_id + getSparepartsByErrorCodeIdDb, + getErrorCodesBySparepartIdDb, + insertErrorCodeSparepartDb, + insertMultipleErrorCodeSparepartsDb, + deleteErrorCodeSparepartDb, + deleteAllErrorCodeSparepartsDb, + updateErrorCodeSparepartsDb, + checkErrorCodeSparepartExistsDb, }; \ No newline at end of file diff --git a/services/brand.service.js b/services/brand.service.js index 84c498d..867f55a 100644 --- a/services/brand.service.js +++ b/services/brand.service.js @@ -9,9 +9,9 @@ const { } = require("../db/brand.db"); const { - insertMultipleBrandSparepartsDb, - updateBrandSparepartsDb, - getSparepartsByBrandIdDb, + insertMultipleErrorCodeSparepartsDb, + updateErrorCodeSparepartsDb, + getSparepartsByErrorCodeIdDb, } = require("../db/brand_sparepart.db"); // Error code operations @@ -41,20 +41,10 @@ class BrandService { try { const results = await getAllBrandsDb(param); - // Add spareparts data for each brand - const brandsWithSpareparts = await Promise.all( - results.data.map(async (brand) => { - const spareparts = await getSparepartsByBrandIdDb(brand.brand_id); - return { - ...brand, - spareparts: spareparts - }; - }) - ); - + // Return brands data - spareparts are now associated with error codes, not brands return { ...results, - data: brandsWithSpareparts + data: results.data }; } catch (error) { throw new ErrorHandler(error.statusCode, error.message); @@ -67,17 +57,17 @@ class BrandService { const brand = await getBrandByIdDb(id); if (!brand) throw new ErrorHandler(404, "Brand not found"); - // Get spareparts for this brand - const spareparts = await getSparepartsByBrandIdDb(brand.brand_id); - const errorCodes = await getErrorCodesByBrandIdDb(brand.brand_id); - const errorCodesWithSolutions = await Promise.all( + const errorCodesWithSolutionsAndSpareparts = await Promise.all( errorCodes.map(async (errorCode) => { const solutions = await getSolutionsByErrorCodeIdDb( errorCode.error_code_id ); + // Get spareparts for this error code + const errorCodeSpareparts = await getSparepartsByErrorCodeIdDb(errorCode.error_code_id); + const solutionsWithFiles = await Promise.all( solutions.map(async (solution) => { let fileData = null; @@ -112,14 +102,14 @@ class BrandService { return { ...errorCode, solution: solutionsWithFiles, + spareparts: errorCodeSpareparts, }; }) ); return { ...brand, - spareparts: spareparts, - error_code: errorCodesWithSolutions, + error_code: errorCodesWithSolutionsAndSpareparts, }; } catch (error) { throw new ErrorHandler(error.statusCode, error.message); @@ -179,10 +169,6 @@ class BrandService { const brandId = createdBrand.brand_id; - if (data.spareparts && Array.isArray(data.spareparts) && data.spareparts.length > 0) { - await insertMultipleBrandSparepartsDb(brandId, data.spareparts, data.created_by); - } - for (const errorCodeData of data.error_code) { const errorId = await createErrorCodeDb(brandId, { error_code: errorCodeData.error_code, @@ -198,6 +184,11 @@ class BrandService { throw new Error("Failed to create error code"); } + // Create sparepart relationships for this error code + if (errorCodeData.spareparts && Array.isArray(errorCodeData.spareparts)) { + await insertMultipleErrorCodeSparepartsDb(errorId, errorCodeData.spareparts, data.created_by); + } + // Create solutions for this error code if (errorCodeData.solution && Array.isArray(errorCodeData.solution)) { for (const solutionData of errorCodeData.solution) { @@ -237,33 +228,14 @@ class BrandService { } } - // Validate sparepart id - static async validateSparepartIds(sparepartIds) { - if (!sparepartIds || !Array.isArray(sparepartIds) || sparepartIds.length === 0) { - return []; - } - - const existingSpareparts = await getSparepartsByIdsDb(sparepartIds); - - if (existingSpareparts.length !== sparepartIds.length) { - const existingIds = existingSpareparts.map(sp => sp.sparepart_id); - const invalidIds = sparepartIds.filter(id => !existingIds.includes(id)); - throw new ErrorHandler(400, `Invalid sparepart IDs: ${invalidIds.join(', ')}`); - } - - return existingSpareparts; - } - + // Update brand static async updateBrandWithFullData(id, data) { try { const existingBrand = await getBrandByIdDb(id); if (!existingBrand) throw new ErrorHandler(404, "Brand not found"); - if (data.spareparts) { - await this.validateSparepartIds(data.spareparts); - } - + if (data.brand_name && data.brand_name !== existingBrand.brand_name) { const brandExists = await checkBrandNameExistsDb(data.brand_name, id); if (brandExists) { @@ -282,10 +254,6 @@ class BrandService { await updateBrandDb(existingBrand.brand_name, brandData); - if (data.spareparts !== undefined) { - await updateBrandSparepartsDb(existingBrand.brand_id, data.spareparts || [], data.updated_by); - } - if (data.error_code && Array.isArray(data.error_code)) { const existingErrorCodes = await getErrorCodesByBrandIdDb(id); const incomingErrorCodes = data.error_code.map((ec) => ec.error_code); @@ -312,6 +280,10 @@ class BrandService { } ); + if (errorCodeData.spareparts && Array.isArray(errorCodeData.spareparts)) { + await updateErrorCodeSparepartsDb(existingEC.error_code_id, errorCodeData.spareparts, data.updated_by); + } + if ( errorCodeData.solution && Array.isArray(errorCodeData.solution) @@ -380,6 +352,10 @@ class BrandService { created_by: data.updated_by, }); + if (errorCodeData.spareparts && Array.isArray(errorCodeData.spareparts)) { + await insertMultipleErrorCodeSparepartsDb(errorId, errorCodeData.spareparts, data.updated_by); + } + if ( errorCodeData.solution && Array.isArray(errorCodeData.solution) diff --git a/validate/brand.schema.js b/validate/brand.schema.js index 5d9d30f..57fe595 100644 --- a/validate/brand.schema.js +++ b/validate/brand.schema.js @@ -10,7 +10,6 @@ const insertBrandSchema = Joi.object({ brand_model: Joi.string().max(100).optional().allow(""), is_active: Joi.boolean().required(), description: Joi.string().max(255).optional().allow(""), - spareparts: Joi.array().items(Joi.number().integer()).optional(), // Array of sparepart_id error_code: Joi.array() .items( Joi.object({ @@ -21,6 +20,7 @@ const insertBrandSchema = Joi.object({ path_icon: Joi.string().optional().allow(""), is_active: Joi.boolean().required(), what_action_to_take: Joi.string().optional().allow(""), + spareparts: Joi.array().items(Joi.number().integer()).optional(), solution: Joi.array() .items( Joi.object({ @@ -57,7 +57,6 @@ const updateBrandSchema = Joi.object({ brand_model: Joi.string().max(100).optional().allow(""), is_active: Joi.boolean().required(), description: Joi.string().max(255).optional().allow(""), - spareparts: Joi.array().items(Joi.number().integer()).optional(), // Array of sparepart_id error_code: Joi.array() .items( Joi.object({ @@ -68,6 +67,7 @@ const updateBrandSchema = Joi.object({ path_icon: Joi.string().optional().allow(""), is_active: Joi.boolean().required(), what_action_to_take: Joi.string().optional().allow(""), + spareparts: Joi.array().items(Joi.number().integer()).optional(), solution: Joi.array() .items( Joi.object({