From 943702dba6b9a79bab5eb7a5219ff2efba62351c Mon Sep 17 00:00:00 2001 From: Vytor Calixto <vytorcalixto@gmail.com> Date: Fri, 27 Apr 2018 11:13:46 -0300 Subject: [PATCH] Refactor classroom count code New requirements not implemented yet --- src/libs/routes/classroomCount.js | 299 ++++++++++++++++++------------ 1 file changed, 184 insertions(+), 115 deletions(-) diff --git a/src/libs/routes/classroomCount.js b/src/libs/routes/classroomCount.js index d78f850c..d0335094 100644 --- a/src/libs/routes/classroomCount.js +++ b/src/libs/routes/classroomCount.js @@ -127,16 +127,6 @@ rqf.addField({ type: 'integer', field: 'ano_censo' } -}).addValue({ - name: 'period', - table: '@', - tableField: 'turma_turno_id', - resultField: 'period_id', - where: { - relation: '=', - type: 'integer', - field: 'turma_turno_id' - } }).addValue({ name: 'school_year', table: '@', @@ -158,22 +148,34 @@ rqf.addField({ field: 'localizacao_id' } }).addValue({ - name: 'education_level_short', + name: 'period', table: '@', - tableField: 'etapa_resumida', - resultField: 'education_level_short_id', + tableField: 'turma_turno_id', + resultField: 'period_id', where: { relation: '=', type: 'integer', - field: 'etapa_resumida' + field: 'turma_turno_id' } }); classroomCountApp.post('/', rqf.parse(), (req, res, next) => { + let classSize = JSON.parse(req.body.class_size) || null; + let integralTime = JSON.parse(req.body.integral_time) || null; + + console.log(classSize, integralTime); + + if(classSize == null || integralTime == null) { + res.statusCode = 400; + return res.json({err: {message: "There was an error processing class_size or integral_time. Check your JSON sintax and be sure you're sending both paramenters."}}); + } + req.classSize = classSize; + req.integralTime = integralTime; + req.dims.state = true; req.dims.city = true; req.dims.period = true; - req.dims.education_level_short = true; + req.dims.school_year = true; req.dims.location = true; req.sql.field('COUNT(*)', 'total') @@ -187,6 +189,28 @@ classroomCountApp.post('/', rqf.parse(), (req, res, next) => { next(); }, rqf.build(), query, id2str.transform(), (req, res, next) => { req.enrollment = req.result; + + // Gera a relação etapa de ensino X ano escolar + req.educationSchoolYear = {}; + for(let i = 10; i < 80; ++i) { + if(id2str.schoolYear(i) !== id2str.schoolYear(99)) { + let educationLevelId = Math.floor(i/10); + + let classSize = req.classSize.find((el) => {return el.id === educationLevelId}); + let integralTime = req.integralTime.find((el) => {return el.id === educationLevelId}); + + let numberStudentClass = (typeof classSize !== 'undefined') ? classSize.numberStudentClass : null; + let offerGoal = (typeof integralTime !== 'undefined') ? integralTime.offerGoal : null; + + req.educationSchoolYear[i] = { + id: educationLevelId, + name: id2str.educationLevelShort(educationLevelId), + numberStudentClass, + offerGoal + }; + } + } + req.resetSql(); next(); }, rqf.parse(), (req, res, next) => { @@ -205,128 +229,173 @@ classroomCountApp.post('/', rqf.parse(), (req, res, next) => { next(); }, rqf.build(), query, id2str.transform(), (req, res, next) => { - let classSize = JSON.parse(req.body.class_size) || null; - let integralTime = JSON.parse(req.body.integral_time) || null; - - console.log(classSize, integralTime); - - if(classSize == null || integralTime == null) { - res.statusCode = 400; - return res.json({err: {message: "There was an error processing class_size or integral_time. Check your JSON sintax and be sure you're sending both paramenters."}}); - } + req.classroom = req.result; let classroom = []; + + // req.result = [{classroom: req.classroom, enrollment: req.enrollment}]; return next(); - req.classroom.forEach((c) => { - let cityObjects = req.classroom.filter((value) => { - return (c.city_id == value.city_id && c.year == value.year); - }); - + // Cria estrutura de resposta requisitada: + let i = 0; + let j = 0; + let result = []; + let hashSet = new Set(); + while (i < req.classroom.length) { + let classroom = req.classroom[i]; + // Cria hash única para cada cidade, dado um ano + let hash = '' + classroom.year + classroom.city_id; + // Estrutura do objeto do resultado final let obj = { - state_id: c.state_id, - state_name: c.state_name, - city_id: c.city_id, - city_name: c.city_name, - year: c.year, + year: classroom.year, + name: classroom.name, + state_id: classroom.state_id, + state_name: classroom.state_name, + city_id: classroom.city_id, + city_name: classroom.city_name, locations: [] }; - cityObjects.forEach((co) => { - obj.locations.push({ - location_id: co.location_id, - location_name: co.location_name, - total_classroom: co.total - }); - }); - - if(classroom.findIndex((el) => {return (el.city_id === obj.city_id && el.year === obj.year)}) === -1) { - classroom.push(obj); + let currentClassroomObj = null; + if( !hashSet.has(hash) ) { + hashSet.add(hash); + result.push(obj); + currentClassroomObj = obj; + } else { // Se a hash já existe, já temos a cidade nos resultados. Como está ordenado, é o último valor nos resultados + currentClassroomObj = result[result.length - 1]; } - }); - let result = []; - // Para cada resultado - classroom.forEach((c) => { - let r = c; - // Para cada localização - c.locations.forEach((location, index) => { - function filterEnrollment(e) { - return (e.city_id == c.city_id && e.year == c.year && e.location_id == location.location_id); + // Inserimos a localidade no array de locations da sala + let location = { + location_id: classroom.location_id, + location_name: classroom.location_name, + total_classroom: parseInt(classroom.total, 10), + total_classroom_be_built: 0, + education_level: [] + }; + currentClassroomObj.locations.push(location); + + // Partimos para as etapas de ensino/anos escolares + + let enrollmentMatch = true; + j = 0; + let educationLevelSet = new Set(); + while(enrollmentMatch && j < req.enrollment.length) { + let enrollment = req.enrollment[j]; + if(typeof enrollment === 'undefined') { + enrollmentMatch = false; + continue; + } + if(enrollment.city_id != classroom.city_id) { // Se as cidades não são iguais, já passamos do range + enrollmentMatch = false; + continue; } - let fEnrollments = req.enrollment.filter(filterEnrollment); - let educationLevels = []; - fEnrollments.forEach((fe) => { - let obj = {education_level_short_id: fe.education_level_short_id, education_level_short_name: fe.education_level_short_name}; + if(enrollment.year != classroom.year || enrollment.location_id != classroom.location_id) { // Se ano ou localização são diferentes, passa para o próximo + ++j; + continue; + } - if(educationLevels.findIndex((el) => {return el.education_level_short_id === obj.education_level_short_id}) === -1 ) { - educationLevels.push(obj); - } - }); + // Remove se o perÃodo é nulo (não dá pra usar no cálculo) + if(enrollment.period_id == null) { + req.enrollment.splice(j, 1); + continue; + } - let education_level = []; - // Para cada etapa de ensino - educationLevels.forEach((eduLevel) => { - function filterEducationLevel(e) { - return (e.city_id == c.city_id && e.year == c.year && e.location_id == location.location_id && e.education_level_short_id == eduLevel.education_level_short_id); + // Temos uma matrÃcula com cidade, ano e localidades certos + // "Consome" a matrÃcula (remove do vetor de matrÃculas) + req.enrollment.splice(j, 1); + + // Cria a etapa de ensino adequada + let enrollmentEducationLevel = req.educationSchoolYear[enrollment.school_year_id]; + // Se não há um número de alunos por turna para a etapa de ensino, ignoramos a entrada + if(enrollmentEducationLevel.numberStudentClass == null) continue; + + let educationLevel = null; + if(!educationLevelSet.has(enrollmentEducationLevel.id)) { + educationLevelSet.add(enrollmentEducationLevel.id); + + educationLevel = { + education_level_short_id: enrollmentEducationLevel.id, + education_level_short_name: enrollmentEducationLevel.name, + enrollment: { + total_enrollment_day: 0, + total_enrollment_night: 0, + full_period_classes: 0, + day_classes: 0, + night_classes: 0, + total_classrooms_needed: 0 + } + }; + + // location.education_level.push(educationLevel); + // Para manter a orde da etapa de ensino + if (location.education_level.length == 0) { + location.education_level.push(educationLevel); + } else { + let k = location.education_level.length - 1; + let el = location.education_level[k]; + while (k >= 0) { + if(educationLevel.education_level_short_id < el.education_level_short_id) { + --k; + if(k>=0) el = location.education_level[k]; + } else break; + } + k++; + location.education_level.splice(k, 0, educationLevel); } + } else { + let k = 0; + let el = location.education_level[k]; + while(k < location.education_level.length) { + if(el.education_level_short_id != enrollmentEducationLevel.id) { + ++k; + if(k<location.education_level.length) el = location.education_level[k]; + } else break; + } + if(k >= location.education_level.length) --k; + educationLevel = location.education_level[k]; + } - let fEducationLevel = fEnrollments.filter(filterEducationLevel); - - let dayEnrollments = 0; - let nightEnrollments = 0; - // Para cada matrÃcula na etapa de ensino - fEducationLevel.forEach((fEduLevel) => { - if(fEduLevel.period_id < 3) dayEnrollments+= fEduLevel.total; - else if(fEduLevel.period_id === 3) nightEnrollments+= fEduLevel.total; - }); - - let size = classSize.find((el) => { - return el.id === eduLevel.education_level_short_id; - }) || undefined; - let fullPeriodTime = integralTime.find((el) => { - return el.id === eduLevel.education_level_short_id; - }) || undefined; - - if(typeof size === 'undefined' || typeof fullPeriodTime === 'undefined') return; - size = size.numberStudentClass; - fullPeriodTime = fullPeriodTime.offerGoal; - - let fullPeriodClasses = Math.ceil((dayEnrollments * (fullPeriodTime / 100))/size); - let dayClasses = Math.ceil((dayEnrollments/size) - fullPeriodClasses); - let nightClasses = Math.ceil(nightEnrollments/size); - let totalClassroomsNeeded = fullPeriodClasses + dayClasses; - - if(nightClasses > dayClasses) totalClassroomsNeeded+= (nightClasses - dayClasses); - - let obj = { - total_enrollment_day : dayEnrollments, - total_enrollment_night: nightEnrollments, - full_period_classes: fullPeriodClasses, - day_classes: dayClasses, - night_classes: nightClasses, - total_classrooms_needed: totalClassroomsNeeded - }; + // Soma os totais de matrÃcula da etapa de ensino + educationLevel.enrollment.total_enrollment_day += (enrollment.period_id < 3 && enrollment.period_id != null) ? enrollment.total : 0; + educationLevel.enrollment.total_enrollment_night += (enrollment.period_id == 3) ? enrollment.total : 0; - let educationLevelIndex = education_level.findIndex((el) => {return el.education_level_short_id === eduLevel.education_level_short_id}); + // Calcula o número de turmas parcial + // Turmas de perÃodo integral + educationLevel.enrollment.full_period_classes = Math.ceil((educationLevel.enrollment.total_enrollment_day * (enrollmentEducationLevel.offerGoal/100)) / enrollmentEducationLevel.numberStudentClass); - if(educationLevelIndex === -1) { - educationLevelIndex = education_level.length; - education_level.push(eduLevel); - } + // Turmas diurnas + educationLevel.enrollment.day_classes = Math.ceil((educationLevel.enrollment.total_enrollment_day / enrollmentEducationLevel.numberStudentClass) - educationLevel.enrollment.full_period_classes); - education_level[educationLevelIndex].enrollment = obj; - // education_level[educationLevelIndex].enrollments = fEducationLevel; - }); + // Turmas noturnas + educationLevel.enrollment.night_classes = Math.ceil((educationLevel.enrollment.total_enrollment_night / enrollmentEducationLevel.numberStudentClass)); - r.locations[index].education_level = education_level; - }); + // Total de salas + educationLevel.enrollment.total_classrooms_needed = (educationLevel.enrollment.full_period_classes + educationLevel.enrollment.day_classes); + + if(educationLevel.enrollment.night_classes > educationLevel.enrollment.day_classes) educationLevel.enrollment.total_classrooms_needed += (educationLevel.enrollment.night_classes - educationLevel.enrollment.day_classes); + + } + + // Calculamos o total classroom be built para o municÃpio usando reduce + location.total_classroom_be_built = location.education_level.reduce((total, atual) => { + return total + atual.enrollment.total_classrooms_needed; + }, 0) - location.total_classroom; + + if(location.total_classroom_be_built < 0) location.total_classroom_be_built = 0; + + ++i; + } + // TODO: agregar por estado e brasil + if(req.query['state']) { + console.log('ESTADO!!!!'); + } else if(!req.query['city']) { + console.log('BRASIL!!!'); + } - result.push(r); - }); - console.log('FEITO'); req.result = result; + next(); }, response('classroom_count')); -- GitLab