diff --git a/src/Controllers/CalculatorController.ts b/src/Controllers/CalculatorController.ts new file mode 100644 index 0000000000000000000000000000000000000000..51a0f43f142915352c4bbe53300d8aad1394805f --- /dev/null +++ b/src/Controllers/CalculatorController.ts @@ -0,0 +1,25 @@ +import { + Handler, Request, Response, Router, +} from 'express'; +import AgeGroupJSON from '../DTOs/AgeGroupJSON'; +import CalculatorService from '../Services/CalculatorService'; +import CalculatorResponse from '../DTOs/CalculatorResponseDTO'; +import logger from '../Logger/logger'; + +const router = Router(); + +const getREP: Handler = async (req: Request, res: Response) => { + const groups: AgeGroupJSON[] = req.body; + try { + const EnergyReq: CalculatorResponse = CalculatorService.calculateEnergeticRequirement(groups); + return res.status(200).send(EnergyReq); + } catch (error) { + const e = error as Error; + logger.info(e.message); + return res.status(400).json({ error: e.message }); + } +}; + +router.post('/', getREP); + +export default router; diff --git a/src/Controllers/ParameterController.ts b/src/Controllers/ParameterController.ts new file mode 100644 index 0000000000000000000000000000000000000000..31e16c9df9d2d7b328348f3338881294cb69c742 --- /dev/null +++ b/src/Controllers/ParameterController.ts @@ -0,0 +1,14 @@ +import { + Handler, Request, Response, Router, +} from 'express'; +import ParameterType from '../Enum/ParameterType'; + +const router = Router(); + +const getParametersOfType: Handler = async (req: Request, res: Response) => { + res.send(); +}; + +router.post('/', getParametersOfType); + +export default router; diff --git a/src/Controllers/SheetController.ts b/src/Controllers/SheetController.ts index 8d784ecbba54fb03dfdd96c6b93631d317229422..8658d81664d845cb843432bd05f3bf7dc91106bd 100644 --- a/src/Controllers/SheetController.ts +++ b/src/Controllers/SheetController.ts @@ -1,24 +1,24 @@ -import { - Handler, Request, Response, Router, -} from 'express'; -import { SheetParserResponse } from '../Models/SheetParserResponse'; -import SheetService from '../Services/SheetService'; -import logger from '../Logger/logger'; - -const router = Router(); - -const parseSheet: Handler = async (req: Request, res: Response) => { - const sheet: Buffer = req.body; - try { - const parsedSheet: SheetParserResponse = SheetService.parseSheetService(sheet); - return res.status(200).send(parsedSheet); - } catch (error) { - const e = error as Error; - logger.info(e.message); - return res.status(400).json({ error: e.message }); - } -}; - -router.post('/', parseSheet); - -export default router; +import { + Handler, Request, Response, Router, +} from 'express'; +import { SheetParserResponse } from '../Models/SheetParserResponse'; +import SheetService from '../Services/SheetService'; +import logger from '../Logger/logger'; + +const router = Router(); + +const parseSheet: Handler = async (req: Request, res: Response) => { + const sheet: Buffer = req.body; + try { + const parsedSheet: SheetParserResponse = SheetService.parseSheetService(sheet); + return res.status(200).send(parsedSheet); + } catch (error) { + const e = error as Error; + logger.info(e.message); + return res.status(400).json({ error: e.message }); + } +}; + +router.post('/', parseSheet); + +export default router; diff --git a/src/DTOs/AgeGroupDTO.ts b/src/DTOs/AgeGroupDTO.ts new file mode 100644 index 0000000000000000000000000000000000000000..5acf22c1c9045c5d83bc02d16868e07b8d2fe4ef --- /dev/null +++ b/src/DTOs/AgeGroupDTO.ts @@ -0,0 +1,11 @@ +import AgeBracket from '../Enum/AgeBracket'; +import Sex from '../Enum/Sex'; + +type AgeGroup = { + edad: AgeBracket; + sexo: Sex; + pesoMediano: number; + cantidad: number; +}; + +export default AgeGroup; diff --git a/src/DTOs/AgeGroupJSON.ts b/src/DTOs/AgeGroupJSON.ts new file mode 100644 index 0000000000000000000000000000000000000000..c8a111c0483005ff9db7a1de541cc14ff063ded7 --- /dev/null +++ b/src/DTOs/AgeGroupJSON.ts @@ -0,0 +1,8 @@ +type AgeGroupJSON = { + edad: string; + sexo: string; + pesoMediano: string; + cantidad: string; +}; + +export default AgeGroupJSON; diff --git a/src/DTOs/CalculatorResponseDTO.ts b/src/DTOs/CalculatorResponseDTO.ts new file mode 100644 index 0000000000000000000000000000000000000000..c4195f7d8f82b03e7d79c0310056e0b2f994a6f3 --- /dev/null +++ b/src/DTOs/CalculatorResponseDTO.ts @@ -0,0 +1,9 @@ +import EnergeticRequirement from './EnergeticRequirementDTO'; +import GroupEnergeticRequirement from './GroupEnergeticRequirementDTO'; + +type CalculatorResponse = { + requerimientosPorGrupo: GroupEnergeticRequirement[]; + requerimientoTotal: EnergeticRequirement; +}; + +export default CalculatorResponse; diff --git a/src/DTOs/EnergeticRequirementDTO.ts b/src/DTOs/EnergeticRequirementDTO.ts new file mode 100644 index 0000000000000000000000000000000000000000..ef11f41e11285421e15b7ff0745744f9be5065e1 --- /dev/null +++ b/src/DTOs/EnergeticRequirementDTO.ts @@ -0,0 +1,7 @@ +type EnergeticRequirement = { + requerimientoEnergeticoPerCapita: number; + requerimientoEnergeticoTotal: number; + poblacionTotal: number; +}; + +export default EnergeticRequirement; diff --git a/src/DTOs/GroupEnergeticRequirementDTO.ts b/src/DTOs/GroupEnergeticRequirementDTO.ts new file mode 100644 index 0000000000000000000000000000000000000000..f0148429ee84ffb5bfdaabeaac73fbdb801c7ce9 --- /dev/null +++ b/src/DTOs/GroupEnergeticRequirementDTO.ts @@ -0,0 +1,9 @@ +import AgeGroupJSON from './AgeGroupJSON'; + +type GroupEnergeticRequirement = { + grupoEtario: AgeGroupJSON; + requerimientoEnergeticoPerCapita: number; + requerimientoEnergeticoTotal: number; +}; + +export default GroupEnergeticRequirement; diff --git a/src/Enum/AgeBracket.ts b/src/Enum/AgeBracket.ts new file mode 100644 index 0000000000000000000000000000000000000000..f3610df9f3b5d86a7861cb90bec46cb76800b016 --- /dev/null +++ b/src/Enum/AgeBracket.ts @@ -0,0 +1,36 @@ +enum AgeBracket { + m0 = '0 meses', + m1 = '1 mes', + m2 = '2 meses', + m3 = '3 meses', + m4 = '4 meses', + m5 = '5 meses', + m6 = '6 meses', + m7 = '7 meses', + m8 = '8 meses', + m9 = '9 meses', + m10 = '10 meses', + m11 = '11 meses', + a1 = '1 año', + a2 = '2 años', + a3 = '3 años', + a4 = '4 años', + a5 = '5 años', + a6 = '6 años', + a7 = '7 años', + a8 = '8 años', + a9 = '9 años', + a10 = '10 años', + a11 = '11 años', + a12 = '12 años', + a13 = '13 años', + a14 = '14 años', + a15 = '15 años', + a16 = '16 años', + a17 = '17 años', + a18_29 = '18-29 años', + a30_59 = '30-59 años', + a60 = '60+ años', +} + +export default AgeBracket; diff --git a/src/Enum/ParameterType.ts b/src/Enum/ParameterType.ts new file mode 100644 index 0000000000000000000000000000000000000000..f2ce0420bf75f91cee0fd4975c474d6e95f1b8ae --- /dev/null +++ b/src/Enum/ParameterType.ts @@ -0,0 +1,8 @@ +enum ParameterType { + NAF = 'NAF', + PesoPorDefecto = 'Peso por defecto', + EmbarazoYLactancia = 'Embarazo y lactancia', + ConstanteDeEcuacion = 'Constante de ecuacion' +} + +export default ParameterType; diff --git a/src/Enum/Sex.ts b/src/Enum/Sex.ts new file mode 100644 index 0000000000000000000000000000000000000000..83d5304cb5cc3b6064b52143d9cf5f765a85806a --- /dev/null +++ b/src/Enum/Sex.ts @@ -0,0 +1,6 @@ +enum Sex { + Masculino = 'Masculino', + Femenino = 'Femenino', +} + +export default Sex; diff --git a/src/Logger/logger.ts b/src/Logger/logger.ts index 17715492a1df299bada6501b3b1a713c91957b09..e14b731dfcbe8ce94fa2790d5995d5d61b1e0e71 100644 --- a/src/Logger/logger.ts +++ b/src/Logger/logger.ts @@ -1,32 +1,32 @@ -import { - createLogger, format, transports, Logger, -} from 'winston'; - -const { - combine, timestamp, -} = format; - -const logger: Logger = createLogger({ - level: 'info', - format: combine( - timestamp(), - format.errors({ stack: true }), - format.json(), - ), - transports: [ - new transports.File({ - level: 'error', - filename: 'logs/error-logs', - maxsize: 104857600, // 100Mb - maxFiles: 3, - }), - new transports.File({ - level: 'info', - filename: 'logs/info-logs', - maxsize: 104857600, // 100Mb - maxFiles: 3, - }), - ], -}); - -export default logger; +import { + createLogger, format, transports, Logger, +} from 'winston'; + +const { + combine, timestamp, +} = format; + +const logger: Logger = createLogger({ + level: 'info', + format: combine( + timestamp(), + format.errors({ stack: true }), + format.json(), + ), + transports: [ + new transports.File({ + level: 'error', + filename: 'logs/error-logs', + maxsize: 104857600, // 100Mb + maxFiles: 3, + }), + new transports.File({ + level: 'info', + filename: 'logs/info-logs', + maxsize: 104857600, // 100Mb + maxFiles: 3, + }), + ], +}); + +export default logger; diff --git a/src/Models/Parameter.ts b/src/Models/Parameter.ts new file mode 100644 index 0000000000000000000000000000000000000000..35b130662806aada16ac16d5ab58836213aa57d2 --- /dev/null +++ b/src/Models/Parameter.ts @@ -0,0 +1,12 @@ +class Parameter { + name: string; + + value: number; + + constructor(name: string, value: number) { + this.name = name; + this.value = value; + } +} + +export default Parameter; diff --git a/src/Models/SheetParserResponse.ts b/src/Models/SheetParserResponse.ts index c29b9e8aa94f52bc8ac2512aba15bbc90e26d29a..f9f64b3b9fb2732428b4172108d5336663f9bf75 100644 --- a/src/Models/SheetParserResponse.ts +++ b/src/Models/SheetParserResponse.ts @@ -1,31 +1,31 @@ -type SheetParserResponse = { - hombresMenores: Menores[] | null; - mujeresMenores: Menores[] | null; - hombres: Mayores[] | null; - mujeres: Mayores[] | null; -} | null; - -type Menores = { - edad: number; - peso: number; -} | null; - -type Mayores = { - edad: number; - peso?: number; - talla?: number; -} | null; - -type MenoresSheet = { - 'Edad (meses)': number; - 'Peso (Kg)': number; -}; -type MayoresSheet = { - 'Edad (años)': number; - 'Peso (Kg)': number; - 'Talla (cm)': number; -}; - -export type { - SheetParserResponse, Menores, Mayores, MenoresSheet, MayoresSheet, -}; +type SheetParserResponse = { + hombresMenores: Menores[] | null; + mujeresMenores: Menores[] | null; + hombres: Mayores[] | null; + mujeres: Mayores[] | null; +} | null; + +type Menores = { + edad: number; + peso: number; +} | null; + +type Mayores = { + edad: number; + peso?: number; + talla?: number; +} | null; + +type MenoresSheet = { + 'Edad (meses)': number; + 'Peso (Kg)': number; +}; +type MayoresSheet = { + 'Edad (años)': number; + 'Peso (Kg)': number; + 'Talla (cm)': number; +}; + +export type { + SheetParserResponse, Menores, Mayores, MenoresSheet, MayoresSheet, +}; diff --git a/src/Services/CalculatorService.ts b/src/Services/CalculatorService.ts new file mode 100644 index 0000000000000000000000000000000000000000..e0f628e668aebe230f458e17a2d1f16af01fefc6 --- /dev/null +++ b/src/Services/CalculatorService.ts @@ -0,0 +1,20 @@ +import ERCalculator from './ERCalculator'; +import ParameterService from './ParameterService'; +import ParserService from './ParserService'; +import AgeGroup from '../DTOs/AgeGroupDTO'; +import CalculatorResponse from '../DTOs/CalculatorResponseDTO'; +import AgeGroupJSON from '../DTOs/AgeGroupJSON'; + +const calculateEnergeticRequirement = (data: AgeGroupJSON[]): CalculatorResponse => { + const parametros = new Map<number[], AgeGroup>(); + const ageGroups = ParserService.parseGroups(data); + ageGroups.forEach((group: AgeGroup) => { + parametros.set(ParameterService.getEquationValues(group.edad, group.sexo), group); + }); + + const res: CalculatorResponse = ERCalculator.calculateER(parametros); + + return res; +}; + +export default { calculateEnergeticRequirement }; diff --git a/src/Services/ERCalculator.ts b/src/Services/ERCalculator.ts new file mode 100644 index 0000000000000000000000000000000000000000..6be7f98ec3b015fe103f03619f1a23943b2b7c81 --- /dev/null +++ b/src/Services/ERCalculator.ts @@ -0,0 +1,90 @@ +import AgeGroup from '../DTOs/AgeGroupDTO'; +import EnergeticRequirement from '../DTOs/EnergeticRequirementDTO'; +import CalculatorResponse from '../DTOs/CalculatorResponseDTO'; +import GroupEnergeticRequirement from '../DTOs/GroupEnergeticRequirementDTO'; +import ParserService from './ParserService'; +import AgeBracket from '../Enum/AgeBracket'; + +const calculateLessThanAYear = (group: AgeGroup, params: number[]): GroupEnergeticRequirement => { + const requirement = params[0] + (params[1] * group.pesoMediano) + params[2]; + + const groupRequirement: GroupEnergeticRequirement = { + grupoEtario: ParserService.unparseGroup(group), + requerimientoEnergeticoPerCapita: requirement, + requerimientoEnergeticoTotal: requirement * group.cantidad, + }; + + return groupRequirement; +}; + +const calculateOneToFiveYears = (group: AgeGroup, params: number[]): GroupEnergeticRequirement => { + const requirement = params[0] + + (params[1] * group.pesoMediano) + + (params[2] * (group.pesoMediano ** 2)) + + params[3]; + + const groupRequirement: GroupEnergeticRequirement = { + grupoEtario: ParserService.unparseGroup(group), + requerimientoEnergeticoPerCapita: requirement, + requerimientoEnergeticoTotal: requirement * group.cantidad, + }; + + return groupRequirement; +}; + +const calculateER = (groupParameters: Map<number[], AgeGroup>): CalculatorResponse => { + let totalOfPeople = 0; + let totalRequirement = 0; + + const requirements: GroupEnergeticRequirement[] = []; + + groupParameters.forEach((group: AgeGroup, params: number[]) => { + totalOfPeople += group.cantidad; + let groupRequirement: GroupEnergeticRequirement; + switch (group.edad) { + case AgeBracket.m0: + case AgeBracket.m1: + case AgeBracket.m2: + case AgeBracket.m3: + case AgeBracket.m4: + case AgeBracket.m5: + case AgeBracket.m6: + case AgeBracket.m7: + case AgeBracket.m8: + case AgeBracket.m9: + case AgeBracket.m10: + case AgeBracket.m11: { + groupRequirement = calculateLessThanAYear(group, params); + break; + } + case AgeBracket.a1: + case AgeBracket.a2: + case AgeBracket.a3: + case AgeBracket.a4: + case AgeBracket.a5: { + groupRequirement = calculateOneToFiveYears(group, params); + break; + } + default: { + throw new Error('Parsing error, attribute edad does not respect format'); + } + } + totalRequirement += groupRequirement.requerimientoEnergeticoTotal; + requirements.push(groupRequirement); + }); + + const totalER: EnergeticRequirement = { + requerimientoEnergeticoPerCapita: totalRequirement / totalOfPeople, + requerimientoEnergeticoTotal: totalRequirement, + poblacionTotal: totalOfPeople, + }; + + const result: CalculatorResponse = { + requerimientosPorGrupo: requirements, + requerimientoTotal: totalER, + }; + + return result; +}; + +export default { calculateER }; diff --git a/src/Services/ParameterService.ts b/src/Services/ParameterService.ts new file mode 100644 index 0000000000000000000000000000000000000000..06ed93dc4f73d86acbecbe63ef2b1195fdd253e1 --- /dev/null +++ b/src/Services/ParameterService.ts @@ -0,0 +1,186 @@ +import AgeBracket from '../Enum/AgeBracket'; +import ParameterType from '../Enum/ParameterType'; +import Sex from '../Enum/Sex'; +// import Parameter from '../Models/Parameter'; + +const getEquationValues = (ageBracket: AgeBracket, sex: Sex): number[] => { + let res: number[] = []; + switch (ageBracket) { + case (AgeBracket.m0): { + if (sex === Sex.Masculino) { + // -152 + (92.8*MP) + 211 + res = [-152, 92.8, 211]; + } else if (sex === Sex.Femenino) { + // -152 + (92.8*MP) + 178 + res = [-152, 92.8, 178]; + } + break; + } + case (AgeBracket.m1): { + if (sex === Sex.Masculino) { + // -152 + (92.8*MP) + 183 + res = [-152, 92.8, 183]; + } else if (sex === Sex.Femenino) { + // -152 + (92.8*MP) + 161 + res = [-152, 92.8, 161]; + } + break; + } + case (AgeBracket.m2): { + if (sex === Sex.Masculino) { + // -152 + (92.8*MP) + 139 + res = [-152, 92.8, 139]; + } else if (sex === Sex.Femenino) { + // -152 + (92.8*MP) + 134 + res = [-152, 92.8, 134]; + } + break; + } + case (AgeBracket.m3): { + if (sex === Sex.Masculino) { + // -152 + (92.8*MP) + 53 + res = [-152, 92.8, 53]; + } else if (sex === Sex.Femenino) { + // -152 + (92.8*MP) + 68 + res = [-152, 92.8, 68]; + } + break; + } + case (AgeBracket.m4): { + if (sex === Sex.Masculino) { + // -152 + (92.8*MP) + 46 + res = [-152, 92.8, 46]; + } else if (sex === Sex.Femenino) { + // -152 + (92.8*MP) + 57 + res = [-152, 92.8, 57]; + } + break; + } + case (AgeBracket.m5): { + if (sex === Sex.Masculino) { + // -152 + (92.8*MP) + 36 + res = [-152, 92.8, 36]; + } else if (sex === Sex.Femenino) { + // -152 + (92.8*MP) + 47 + res = [-152, 92.8, 47]; + } + break; + } + case (AgeBracket.m6): { + if (sex === Sex.Masculino) { + // -99.4 + (88.6*MP) + 17 + res = [-99.4, 88.6, 17]; + } else if (sex === Sex.Femenino) { + // -99.4 + (88.6*MP) + 20 + res = [-99.4, 88.6, 20]; + } + break; + } + case (AgeBracket.m7): { + if (sex === Sex.Masculino) { + // -99.4 + (88.6*MP) + 16 + res = [-99.4, 88.6, 16]; + } else if (sex === Sex.Femenino) { + // -99.4 + (88.6*MP) + 17 + res = [-99.4, 88.6, 17]; + } + break; + } + case (AgeBracket.m8): { + if (sex === Sex.Masculino) { + // -99.4 + (88.6*MP) + 14 + res = [-99.4, 88.6, 14]; + } else if (sex === Sex.Femenino) { + // -99.4 + (88.6*MP) + 15 + res = [-99.4, 88.6, 15]; + } + break; + } + case (AgeBracket.m9): { + if (sex === Sex.Masculino) { + // -99.4 + (88.6*MP) + 21 + res = [-99.4, 88.6, 21]; + } else if (sex === Sex.Femenino) { + // -99.4 + (88.6*MP) + 18 + res = [-99.4, 88.6, 18]; + } + break; + } + case (AgeBracket.m10): { + if (sex === Sex.Masculino) { + // -99.4 + (88.6*MP) + 21 + res = [-99.4, 88.6, 21]; + } else if (sex === Sex.Femenino) { + // -99.4 + (88.6*MP) + 15 + res = [-99.4, 88.6, 15]; + } + break; + } + case (AgeBracket.m11): { + if (sex === Sex.Masculino) { + // -99.4 + (88.6*MP) + 22 + res = [-99.4, 88.6, 22]; + } else if (sex === Sex.Femenino) { + // -99.4 + (88.6*MP) + 14 + res = [-99.4, 88.6, 14]; + } + break; + } + case (AgeBracket.a1): { + if (sex === Sex.Masculino) { + // 310.2 + (63.3*MP) - 0.263*MP^2 + 13 + res = [310.2, 63.3, -0.263, 13]; + } else if (sex === Sex.Femenino) { + // 263.4 + (65.3*MP) - 0.454*MP^2 + 13 + res = [263.4, 65.3, -0.454, 13]; + } + break; + } + case (AgeBracket.a2): { + if (sex === Sex.Masculino) { + // 310.2 + (63.3*MP) - 0.263*MP^2 + 12 + res = [310.2, 63.3, -0.263, 12]; + } else if (sex === Sex.Femenino) { + // 263.4 + (65.3*MP) - 0.454*MP^2 + 13 + res = [263.4, 65.3, -0.454, 13]; + } + break; + } + case (AgeBracket.a3): { + if (sex === Sex.Masculino) { + // 310.2 + (63.3*MP) - 0.263*MP^2 + 12 + res = [310.2, 63.3, -0.263, 12]; + } else if (sex === Sex.Femenino) { + // 263.4 + (65.3*MP) - 0.454*MP^2 + 11 + res = [263.4, 65.3, -0.454, 11]; + } + break; + } + case (AgeBracket.a4): { + if (sex === Sex.Masculino) { + // 310.2 + (63.3*MP) - 0.263*MP^2 + 11 + res = [310.2, 63.3, -0.263, 11]; + } else if (sex === Sex.Femenino) { + // 263.4 + (65.3*MP) - 0.454*MP^2 + 10 + res = [263.4, 65.3, -0.454, 10]; + } + break; + } + case (AgeBracket.a5): { + if (sex === Sex.Masculino) { + // 310.2 + (63.3*MP) - 0.263*MP^2 + 11 + res = [310.2, 63.3, -0.263, 11]; + } else if (sex === Sex.Femenino) { + // 263.4 + (65.3*MP) - 0.454*MP^2 + 10 + res = [263.4, 65.3, -0.454, 10]; + } + break; + } + default: { + throw new Error('Parsing error, attribute edad does not respect format'); + } + } + return res; +}; + +export default { getEquationValues }; diff --git a/src/Services/ParserService.ts b/src/Services/ParserService.ts new file mode 100644 index 0000000000000000000000000000000000000000..b9aedc9f4780a9abb1ce2a9a84019154efadb655 --- /dev/null +++ b/src/Services/ParserService.ts @@ -0,0 +1,190 @@ +import AgeGroup from '../DTOs/AgeGroupDTO'; +import AgeGroupJSON from '../DTOs/AgeGroupJSON'; +import AgeBracket from '../Enum/AgeBracket'; +import Sex from '../Enum/Sex'; + +// const parseSex = (sexo: string): Sex => { +// let sex: Sex = sexo; +// switch (sexo) { +// case 'Masculino': { +// sex = Sex.Masculino; +// break; +// } +// case 'Femenino': { +// sex = Sex.Femenino; +// break; +// } +// default: { +// throw new Error('Parsing error, attribute sexo does not respect format'); +// } +// } +// return sex; +// }; +// +// const parseAge = (edad: string): AgeBracket => { +// let age: AgeBracket; +// switch (edad) { +// case '0 meses': { +// age = AgeBracket.m0; +// break; +// } +// case '1 mes': { +// age = AgeBracket.m1; +// break; +// } +// case '2 meses': { +// age = AgeBracket.m2; +// break; +// } +// case '3 meses': { +// age = AgeBracket.m3; +// break; +// } +// case '4 meses': { +// age = AgeBracket.m4; +// break; +// } +// case '5 meses': { +// age = AgeBracket.m5; +// break; +// } +// case '6 meses': { +// age = AgeBracket.m6; +// break; +// } +// case '7 meses': { +// age = AgeBracket.m7; +// break; +// } +// case '8 meses': { +// age = AgeBracket.m8; +// break; +// } +// case '9 meses': { +// age = AgeBracket.m9; +// break; +// } +// case '10 meses': { +// age = AgeBracket.m10; +// break; +// } +// case '11 meses': { +// age = AgeBracket.m11; +// break; +// } +// case '1 año': { +// age = AgeBracket.a1; +// break; +// } +// case '2 años': { +// age = AgeBracket.a2; +// break; +// } +// case '3 años': { +// age = AgeBracket.a3; +// break; +// } +// case '4 años': { +// age = AgeBracket.a4; +// break; +// } +// case '5 años': { +// age = AgeBracket.a5; +// break; +// } +// case '6 años': { +// age = AgeBracket.a6; +// break; +// } +// case '7 años': { +// age = AgeBracket.a7; +// break; +// } +// case '8 años': { +// age = AgeBracket.a8; +// break; +// } +// case '9 años': { +// age = AgeBracket.a9; +// break; +// } +// case '10 años': { +// age = AgeBracket.a10; +// break; +// } +// case '11 años': { +// age = AgeBracket.a11; +// break; +// } +// case '12 años': { +// age = AgeBracket.a12; +// break; +// } +// case '13 años': { +// age = AgeBracket.a13; +// break; +// } +// case '14 años': { +// age = AgeBracket.a14; +// break; +// } +// case '15 años': { +// age = AgeBracket.a15; +// break; +// } +// case '16 años': { +// age = AgeBracket.a16; +// break; +// } +// case '17 años': { +// age = AgeBracket.a17; +// break; +// } +// case '18-29 años': { +// age = AgeBracket.a18_29; +// break; +// } +// case '30-59 años': { +// age = AgeBracket.a30_59; +// break; +// } +// case '60+ años': { +// age = AgeBracket.a60; +// break; +// } +// default: { +// throw new Error('Parsing error, attribute edad does not respect format'); +// } +// } +// return age; +// }; + +const parseGroups = (groups: AgeGroupJSON[]): AgeGroup[] => { + const retGroups: AgeGroup[] = []; + groups.forEach((obj: AgeGroupJSON) => { + // if (typeof (obj.pesoMediano) !== 'number' || typeof (obj.cantidad) !== 'number') { + // console.log('Estas haciendo cualquiera flaco'); + // throw new Error('Parsing error, attributes do not respect format'); + // } + const group: AgeGroup = { + edad: obj.edad as AgeBracket, + sexo: obj.sexo as Sex, + pesoMediano: parseFloat(obj.pesoMediano), + cantidad: parseFloat(obj.cantidad), + }; + retGroups.push(group); + }); + return retGroups; +}; + +const unparseGroup = (group: AgeGroup): AgeGroupJSON => { + const retGroup: AgeGroupJSON = { + edad: group.edad as string, + sexo: group.sexo as string, + pesoMediano: String(group.pesoMediano), + cantidad: String(group.cantidad), + }; + return retGroup; +}; + +export default { parseGroups, unparseGroup }; diff --git a/src/Services/SheetService.ts b/src/Services/SheetService.ts index 947b1b0998d3b74ea107177cfbbd297d41962c12..e30e75a1e5f332c98a5a69bf0670a1e916313cd9 100644 --- a/src/Services/SheetService.ts +++ b/src/Services/SheetService.ts @@ -1,108 +1,108 @@ -import * as XLSX from 'xlsx'; -import { SheetNames } from '../Config/Constants'; -import { - SheetParserResponse, Menores, Mayores, MenoresSheet, MayoresSheet, -} from '../Models/SheetParserResponse'; - -/* PRIVATE FUNCTIONS */ -// const ec = (r: number, c: number): string => XLSX.utils.encode_cell({ r, c }); -// const deleteRow = (ws: XLSX.WorkSheet, rowIndex: number): XLSX.WorkSheet => { -// const work = ws; -// if (work['!ref'] === undefined) throw new Error('An error has ocurred in deleteRow'); -// const variable = XLSX.utils.decode_range(work['!ref']); -// for (let R = rowIndex; R < variable.e.r; R += 1) { -// for (let C = variable.s.c; C <= variable.e.c; C += 1) { -// work[ec(R, C)] = work[ec(R + 1, C)]; -// } -// } -// variable.e.r -= 1; -// work['!ref'] = XLSX.utils.encode_range(variable.s, variable.e); -// return work; -// }; - -const parseAdults = (worksheet: XLSX.WorkSheet): Mayores[] => { - const res: Mayores[] = []; - const ref = worksheet['!ref']; - if (ref === undefined) throw new Error('An error ocurred'); - const range = XLSX.utils.decode_range(ref); - range.s.c = 0; - range.e.c = 2; - const newRange = XLSX.utils.encode_range(range); - - const aux = XLSX.utils.sheet_to_json(worksheet, { range: newRange }) as unknown as MayoresSheet[]; - - aux.forEach((element: MayoresSheet) => { - res.push( - { - edad: element['Edad (años)'], - peso: element['Peso (Kg)'], - talla: element['Talla (cm)'], - }, - ); - }); - return res; -}; - -const parseBabies = (worksheet: XLSX.WorkSheet): Menores[] => { - const res: Menores[] = []; - const aux = XLSX.utils.sheet_to_json(worksheet) as unknown as MenoresSheet[]; - aux.forEach((element: MenoresSheet) => { - res.push( - { - edad: element['Edad (meses)'], - peso: element['Peso (Kg)'], - }, - ); - }); - return res; -}; - -/* EXPORT FUNCTIONS */ - -const parseSheetService = (data: Buffer): SheetParserResponse => { - const workbook: XLSX.WorkBook = XLSX.read(data); - let parsed: SheetParserResponse = null; - let hombresMenores: Menores[] = []; - let hombres: Mayores[] = []; - let mujeresMenores: Menores[] = []; - let mujeres: Mayores[] = []; - - const sheetNames: string[] = workbook.SheetNames; - // Check there are 4 sheets, no more, no less - if (sheetNames.length !== 4) { - throw new Error('File does not respect scheme, there are more or less than 4 sheets'); - } - sheetNames.forEach((name) => { - const worksheet: XLSX.WorkSheet = workbook.Sheets[name]; - switch (name) { - case SheetNames.HOMBRES_MENORES: - hombresMenores = parseBabies(worksheet); - break; - case SheetNames.HOMBRES: - hombres = parseAdults(worksheet); - break; - case SheetNames.MUJERES_MENORES: - mujeresMenores = parseBabies(worksheet); - break; - case SheetNames.MUJERES: - mujeres = parseAdults(worksheet); - break; - - default: - throw new Error(`Sheet name ${name} is not part of the scheme `); - } - }); - parsed = { - hombresMenores, - hombres, - mujeresMenores, - mujeres, - }; - - return parsed; - // TODO: depends on sheet layout what to do -}; - -export default { - parseSheetService, -}; +import * as XLSX from 'xlsx'; +import { SheetNames } from '../Config/Constants'; +import { + SheetParserResponse, Menores, Mayores, MenoresSheet, MayoresSheet, +} from '../Models/SheetParserResponse'; + +/* PRIVATE FUNCTIONS */ +// const ec = (r: number, c: number): string => XLSX.utils.encode_cell({ r, c }); +// const deleteRow = (ws: XLSX.WorkSheet, rowIndex: number): XLSX.WorkSheet => { +// const work = ws; +// if (work['!ref'] === undefined) throw new Error('An error has ocurred in deleteRow'); +// const variable = XLSX.utils.decode_range(work['!ref']); +// for (let R = rowIndex; R < variable.e.r; R += 1) { +// for (let C = variable.s.c; C <= variable.e.c; C += 1) { +// work[ec(R, C)] = work[ec(R + 1, C)]; +// } +// } +// variable.e.r -= 1; +// work['!ref'] = XLSX.utils.encode_range(variable.s, variable.e); +// return work; +// }; + +const parseAdults = (worksheet: XLSX.WorkSheet): Mayores[] => { + const res: Mayores[] = []; + const ref = worksheet['!ref']; + if (ref === undefined) throw new Error('An error ocurred'); + const range = XLSX.utils.decode_range(ref); + range.s.c = 0; + range.e.c = 2; + const newRange = XLSX.utils.encode_range(range); + + const aux = XLSX.utils.sheet_to_json(worksheet, { range: newRange }) as unknown as MayoresSheet[]; + + aux.forEach((element: MayoresSheet) => { + res.push( + { + edad: element['Edad (años)'], + peso: element['Peso (Kg)'], + talla: element['Talla (cm)'], + }, + ); + }); + return res; +}; + +const parseBabies = (worksheet: XLSX.WorkSheet): Menores[] => { + const res: Menores[] = []; + const aux = XLSX.utils.sheet_to_json(worksheet) as unknown as MenoresSheet[]; + aux.forEach((element: MenoresSheet) => { + res.push( + { + edad: element['Edad (meses)'], + peso: element['Peso (Kg)'], + }, + ); + }); + return res; +}; + +/* EXPORT FUNCTIONS */ + +const parseSheetService = (data: Buffer): SheetParserResponse => { + const workbook: XLSX.WorkBook = XLSX.read(data); + let parsed: SheetParserResponse = null; + let hombresMenores: Menores[] = []; + let hombres: Mayores[] = []; + let mujeresMenores: Menores[] = []; + let mujeres: Mayores[] = []; + + const sheetNames: string[] = workbook.SheetNames; + // Check there are 4 sheets, no more, no less + if (sheetNames.length !== 4) { + throw new Error('File does not respect scheme, there are more or less than 4 sheets'); + } + sheetNames.forEach((name) => { + const worksheet: XLSX.WorkSheet = workbook.Sheets[name]; + switch (name) { + case SheetNames.HOMBRES_MENORES: + hombresMenores = parseBabies(worksheet); + break; + case SheetNames.HOMBRES: + hombres = parseAdults(worksheet); + break; + case SheetNames.MUJERES_MENORES: + mujeresMenores = parseBabies(worksheet); + break; + case SheetNames.MUJERES: + mujeres = parseAdults(worksheet); + break; + + default: + throw new Error(`Sheet name ${name} is not part of the scheme `); + } + }); + parsed = { + hombresMenores, + hombres, + mujeresMenores, + mujeres, + }; + + return parsed; + // TODO: depends on sheet layout what to do +}; + +export default { + parseSheetService, +}; diff --git a/src/index.ts b/src/index.ts index 30dad1b806cb360a6b93e61524f8477ef8616086..619878283eba6bf5ab35ecee900a2ea69a982517 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,39 +1,39 @@ -/* eslint-disable no-console */ -import express, { Application } from 'express'; -import 'dotenv/config'; -import cors from 'cors'; -import swaggerUi from 'swagger-ui-express'; -import helmet from 'helmet'; -import YAML from 'yamljs'; -import Routes from './routes'; -import logger from './Logger/logger'; - -const app: Application = express(); -const PORT = process.env.PORT || 8000; -app.use(helmet.hidePoweredBy()); -// swagger init -const swaggerDocument = YAML.load('./swagger.yaml'); -// middlewares -app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument)); - -app.use(express.json({ - limit: '50mb', -})); -app.use(express.urlencoded({ extended: false })); -app.use(cors({ - origin: '*', - methods: 'GET,HEAD,PUT,PATCH,POST,DELETE', - preflightContinue: false, - optionsSuccessStatus: 204, -})); - -app.use(express.raw({ - limit: '50mb', -})); - -app.use(Routes); - -app.listen(PORT, (): void => { - console.log(`REPP Backend running here 👉 https://localhost:${PORT}`); - logger.info('Server initiated'); -}); +/* eslint-disable no-console */ +import express, { Application } from 'express'; +import 'dotenv/config'; +import cors from 'cors'; +import swaggerUi from 'swagger-ui-express'; +import helmet from 'helmet'; +import YAML from 'yamljs'; +import Routes from './routes'; +import logger from './Logger/logger'; + +const app: Application = express(); +const PORT = process.env.PORT || 8000; +app.use(helmet.hidePoweredBy()); +// swagger init +const swaggerDocument = YAML.load('./swagger.yaml'); +// middlewares +app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument)); + +app.use(express.json({ + limit: '50mb', +})); +app.use(express.urlencoded({ extended: false })); +app.use(cors({ + origin: '*', + methods: 'GET,HEAD,PUT,PATCH,POST,DELETE', + preflightContinue: false, + optionsSuccessStatus: 204, +})); + +app.use(express.raw({ + limit: '50mb', +})); + +app.use(Routes); + +app.listen(PORT, (): void => { + console.log(`REPP Backend running here 👉 https://localhost:${PORT}`); + logger.info('Server initiated'); +}); diff --git a/src/routes.ts b/src/routes.ts index ed8df5918a887121d647a539d424ec5e25525a09..c0ea909c381728d2b0e3a226166ec8e1f4102f4e 100644 --- a/src/routes.ts +++ b/src/routes.ts @@ -1,12 +1,18 @@ -import { Request, Response, Router } from 'express'; -import SheetController from './Controllers/SheetController'; - -const router = Router(); - -router.get('/', (req: Request, res: Response): void => { - res.send('Hey! This is REPP API, you can go to /api-docs to learn more!'); -}); - -router.use('/sheetParser', SheetController); - -export default router; +import { Request, Response, Router } from 'express'; +import SheetController from './Controllers/SheetController'; +import CalculatorController from './Controllers/CalculatorController'; +import ParameterController from './Controllers/ParameterController'; + +const router = Router(); + +router.get('/', (req: Request, res: Response): void => { + res.send('Hey! This is REPP API, you can go to /api-docs to learn more!'); +}); + +router.use('/sheetParser', SheetController); + +router.use('/repCalculator', CalculatorController); + +router.use('/parameters', ParameterController); + +export default router; diff --git a/swagger.yaml b/swagger.yaml index b424dc77f3b74ba186b84b58830e3557723265d0..a531d9d80720a482901607fbe7aa5350473c9656 100644 --- a/swagger.yaml +++ b/swagger.yaml @@ -44,6 +44,23 @@ paths: description: Ok. security: - BearerAuth: [] + + /repCalculator: + post: + tags: + - Calculation + summary: Given population data calculates its energetic requirement + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AgeGroupJSON' + required: true + responses: + '200': + description: Ok. + security: + - BearerAuth: [] components: securitySchemes: BearerAuth: @@ -88,3 +105,13 @@ components: type: string pass: type: string + AgeGroupJSON: + properties: + edad: + type: string + sexo: + type: string + pesoMediano: + type: string + cantidad: + type: string \ No newline at end of file