diff --git a/src/controllers/fichas-tombos-controller.js b/src/controllers/fichas-tombos-controller.js index 3ac52a8c..6d1e689b 100644 --- a/src/controllers/fichas-tombos-controller.js +++ b/src/controllers/fichas-tombos-controller.js @@ -41,7 +41,13 @@ function formataDataSaida(data) { export default function fichaTomboController(request, response, next) { const { tombo_id: tomboId } = request.params; - const { qtd } = request.query; + const { qtd, code } = request.query; + + if (qtd < 1) { + Promise.reject(new Error('Quantidade inválida')); + } else if (qtd > 3) { + Promise.reject(new Error('Quantidade máxima de 3 itens excedida')); + } Promise.resolve() .then(() => { @@ -97,7 +103,7 @@ export default function fichaTomboController(request, response, next) { model: LocalColeta, include: [ { - required: true, + required: false, model: Cidade, include: { required: true, @@ -123,10 +129,11 @@ export default function fichaTomboController(request, response, next) { const where = { ativo: true, - hcf: tomboId, + hcf: parseInt(tomboId), }; - return Tombo.findOne({ include, where }); + const tombo = Tombo.findOne({ include, where }); + return tombo; }) .then(tombo => { if (!tombo) { @@ -197,9 +204,9 @@ export default function fichaTomboController(request, response, next) { const coletores = `${tombo.coletore.nome}${tombo.coletor_complementar ? tombo.coletor_complementar.complementares : ''}`; const localColeta = tombo.local_coleta; - const { cidade } = localColeta; - const { estado } = cidade; - const { pais } = estado; + const cidade = localColeta.cidade || ''; + const estado = cidade?.estado || ''; + const pais = estado?.pais || ''; const romanos = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII']; const dataTombo = new Date(tombo.data_tombo); @@ -252,6 +259,7 @@ export default function fichaTomboController(request, response, next) { romano_data_identificacao: romanoDataIdentificacao, romano_data_coleta: romanoDataColeta, numero_copias: qtd || 1, + codigo_barras_selecionado: code, }; const caminhoArquivoHtml = path.resolve(__dirname, '../views/ficha-tombo.ejs'); diff --git a/src/controllers/locais-coleta-controller.js b/src/controllers/locais-coleta-controller.js index 771a7ef3..5d574454 100644 --- a/src/controllers/locais-coleta-controller.js +++ b/src/controllers/locais-coleta-controller.js @@ -1,9 +1,11 @@ +import pick from '~/helpers/pick'; + import BadRequestExeption from '../errors/bad-request-exception'; import models from '../models'; import codigos from '../resources/codigos-http'; const { - Relevo, Solo, Vegetacao, sequelize, + Relevo, Solo, Vegetacao, LocalColeta, Cidade, FaseSucessional, Estado, Pais, sequelize, } = models; export const cadastrarSolo = (request, response, next) => { @@ -120,4 +122,158 @@ export const buscarVegetacoes = (request, response, next) => { .catch(next); }; +export const cadastrarLocalColeta = async (request, response, next) => { + try { + const dados = pick(request.body, ['descricao', 'complemento', 'cidade_id', 'fase_sucessional_id']); + const localColeta = await LocalColeta.create(dados); + response.status(201).json(localColeta); + } catch (error) { + next(error); + } +}; + +export const buscarLocaisColeta = async (request, response, next) => { + try { + const { cidade_id: cidadeId } = request.query; + const { limite, pagina, offset } = request.paginacao; + + const where = {}; + if (cidadeId) { + where.cidade_id = cidadeId; + } + + const { count, rows } = await LocalColeta.findAndCountAll({ + where, + include: [ + { model: Cidade, + include: [ + { model: Estado, + include: [ + Pais, + ], + }, + ], + }, + { model: FaseSucessional }, + ], + limit: limite, + offset, + }); + + response.status(200).json({ + metadados: { + total: count, + pagina, + limite, + }, + resultado: rows, + }); + } catch (error) { + next(error); + } +}; + +export const buscarLocalColetaPorId = async (request, response, next) => { + try { + const { id } = request.params; + + const localColeta = await LocalColeta.findOne({ + where: { id }, + include: [ + { model: Cidade, + include: [ + { model: Estado, + include: [ + Pais, + ], + }, + ], + }, + { model: FaseSucessional }, + ], + }); + + if (!localColeta) { + response.status(404).json({ + mensagem: 'Local de coleta não encontrado.', + }); + return; + } + + response.status(200).json(localColeta); + } catch (error) { + next(error); + } +}; + +export const atualizarLocalColeta = async (request, response, next) => { + try { + const { id } = request.params; + const dados = pick(request.body, ['descricao', 'complemento', 'cidade_id', 'fase_sucessional_id']); + + const [updated] = await LocalColeta.update(dados, { + where: { id }, + }); + + if (updated === 0) { + response.status(404).json({ + mensagem: 'Local de coleta não encontrado.', + }); + return; + } + + const localColetaAtualizado = await LocalColeta.findOne({ + where: { id }, + include: [ + { model: Cidade }, + { model: FaseSucessional }, + ], + }); + + response.status(200).json(localColetaAtualizado); + } catch (error) { + next(error); + } +}; + +export const deletarLocalColeta = async (request, response, next) => { + try { + const { id } = request.params; + + const localColeta = await LocalColeta.findOne({ + where: { id }, + }); + + if (!localColeta) { + response.status(404).json({ + mensagem: 'Local de coleta não encontrado.', + }); + return; + } + + const { Tombo } = models; + const tombosAssociados = await Tombo.count({ + where: { + local_coleta_id: id, + ativo: true, + }, + }); + + if (tombosAssociados > 0) { + response.status(400).json({ + mensagem: `Não é possível excluir o local de coleta. Existem ${tombosAssociados} tombo(s) associado(s) a este local.`, + }); + return; + } + + await LocalColeta.destroy({ + where: { id }, + }); + + response.status(204).send(); + + } catch (error) { + next(error); + } +}; export default {}; diff --git a/src/controllers/pendencias-controller.js b/src/controllers/pendencias-controller.js index 6c8dc919..b90553ee 100644 --- a/src/controllers/pendencias-controller.js +++ b/src/controllers/pendencias-controller.js @@ -5,7 +5,6 @@ import codigos from '../resources/codigos-http'; const { Alteracao, - Autor, Usuario, Herbario, Solo, @@ -17,7 +16,6 @@ const { sequelize, Sequelize: { Op }, Tombo, - TomboColetor, Especie, Variedade, Coletor, @@ -29,6 +27,7 @@ const { ColecaoAnexa, TomboIdentificador, Identificador, + ColetorComplementar, } = models; export const listagem = (request, response, next) => { @@ -1097,549 +1096,438 @@ export const visualizarAlteracaoOperador = (json, alteracao, transaction) => { }); }; -async function atualizarIdentificadoresDeTombo(tomboHcf, novosIdentificadores) { - return sequelize.transaction(async transaction => { - await TomboIdentificador.destroy({ +export const aprovarPendencia = async (alteracao, hcf, transaction) => { + if (!alteracao || !hcf) { + throw new BadRequestExeption(404); + } + + const tomboAtual = await Tombo.findOne({ + where: { hcf, ativo: true }, + transaction, + raw: true, + nest: true, + }); + + if (!tomboAtual) { + throw new BadRequestExeption(404); + } + + const updateTombo = {}; + const nomesCientificosPartes = []; + + if (alteracao.nomes_populares !== undefined) { + updateTombo.nomes_populares = alteracao.nomes_populares; + } + + if (alteracao.numero_coleta !== undefined) { + updateTombo.numero_coleta = alteracao.numero_coleta; + } + + if (alteracao.observacao !== undefined) { + updateTombo.observacao = alteracao.observacao; + } + + if (alteracao.cor !== undefined) { + updateTombo.cor = alteracao.cor.toUpperCase(); + } + + if (alteracao.data_coleta_dia !== undefined) { + updateTombo.data_coleta_dia = alteracao.data_coleta_dia; + } + + if (alteracao.data_coleta_mes !== undefined) { + updateTombo.data_coleta_mes = alteracao.data_coleta_mes; + } + + if (alteracao.data_coleta_ano !== undefined) { + updateTombo.data_coleta_ano = alteracao.data_coleta_ano; + } + + if (alteracao.data_identificacao_dia !== undefined) { + updateTombo.data_identificacao_dia = alteracao.data_identificacao_dia; + } + + if (alteracao.data_identificacao_mes !== undefined) { + updateTombo.data_identificacao_mes = alteracao.data_identificacao_mes; + } + + if (alteracao.data_identificacao_ano !== undefined) { + updateTombo.data_identificacao_ano = alteracao.data_identificacao_ano; + } + + if (alteracao.latitude !== undefined) { + updateTombo.latitude = typeof alteracao.latitude === 'string' + ? converteParaDecimal(alteracao.latitude) + : alteracao.latitude; + } + + if (alteracao.longitude !== undefined) { + updateTombo.longitude = typeof alteracao.longitude === 'string' + ? converteParaDecimal(alteracao.longitude) + : alteracao.longitude; + } + + if (alteracao.altitude !== undefined) { + updateTombo.altitude = alteracao.altitude; + } + + if (alteracao.entidade_id) { + const herbario = await Herbario.findOne({ + where: { id: alteracao.entidade_id }, + transaction, + raw: true, + nest: true, + }); + + if (!herbario) { + throw new BadRequestExeption(404); + } + updateTombo.entidade_id = alteracao.entidade_id; + } + + if (alteracao.tipo_id) { + const tipo = await Tipo.findOne({ + where: { id: alteracao.tipo_id }, + transaction, + raw: true, + nest: true, + }); + + if (!tipo) { + throw new BadRequestExeption(404); + } + updateTombo.tipo_id = alteracao.tipo_id; + } + + if (alteracao.familia_id) { + const familia = await Familia.findOne({ + where: { id: alteracao.familia_id }, + transaction, + raw: true, + nest: true, + }); + + if (!familia) { + throw new BadRequestExeption(404); + } + + updateTombo.familia_id = alteracao.familia_id; + nomesCientificosPartes.push(familia.nome); + + updateTombo.sub_familia_id = null; + updateTombo.genero_id = null; + updateTombo.especie_id = null; + updateTombo.sub_especie_id = null; + updateTombo.variedade_id = null; + } + + if (alteracao.sub_familia_id) { + const subfamilia = await Subfamilia.findOne({ where: { - tombo_hcf: tomboHcf, + id: alteracao.sub_familia_id, + familia_id: updateTombo.familia_id || tomboAtual.familia_id, }, transaction, + raw: true, + nest: true, }); - const novosIdentificadoresPromise = novosIdentificadores.map((identificadorId, index) => - TomboIdentificador.create( - { - tombo_hcf: tomboHcf, - identificador_id: identificadorId, - ordem: index + 1, - }, - { - transaction, - } - ) - ); + if (!subfamilia) { + throw new BadRequestExeption(404); + } - await Promise.all(novosIdentificadoresPromise); - }); -} + updateTombo.sub_familia_id = alteracao.sub_familia_id; + nomesCientificosPartes.push(subfamilia.nome); + + updateTombo.genero_id = null; + updateTombo.especie_id = null; + updateTombo.sub_especie_id = null; + updateTombo.variedade_id = null; + } + + if (alteracao.genero_id) { + const genero = await Genero.findOne({ + where: { + id: alteracao.genero_id, + familia_id: updateTombo.familia_id || tomboAtual.familia_id, + }, + transaction, + raw: true, + nest: true, + }); + + if (!genero) { + throw new BadRequestExeption(404); + } -export const aprovarComJson = async (changes, hcf, response, next) => { - const alteracao = changes; + updateTombo.genero_id = alteracao.genero_id; + nomesCientificosPartes.push(genero.nome); - if (alteracao.identificadores) { - // identificadoresObjeto.usuario_id = alteracao.identificadores; - await atualizarIdentificadoresDeTombo(hcf, alteracao.identificadores); + updateTombo.especie_id = null; + updateTombo.sub_especie_id = null; + updateTombo.variedade_id = null; } - return Promise.resolve() - .then(() => { - if (alteracao.familia_id) { - if (!alteracao.sub_familia_id) { - alteracao.sub_familia_id = null; - } - if (!alteracao.genero_id) { - alteracao.genero_id = null; - } - if (!alteracao.especie_id) { - alteracao.especie_id = null; - } - if (!alteracao.sub_especie_id) { - alteracao.sub_especie_id = null; - } - if (!alteracao.variedade_id) { - alteracao.variedade_id = null; - } - } + if (alteracao.especie_id) { + const especie = await Especie.findOne({ + where: { + id: alteracao.especie_id, + genero_id: updateTombo.genero_id || tomboAtual.genero_id, + }, + transaction, + raw: true, + nest: true, + }); - if (alteracao.genero_id) { - if (!alteracao.especie_id) { - alteracao.especie_id = null; - } - if (!alteracao.sub_especie_id) { - alteracao.sub_especie_id = null; - } - if (!alteracao.variedade_id) { - alteracao.variedade_id = null; - } - } + if (!especie) { + throw new BadRequestExeption(404); + } - if (alteracao.especie_id) { - if (!alteracao.sub_especie_id) { - alteracao.sub_especie_id = null; - } - if (!alteracao.variedade_id) { - alteracao.variedade_id = null; - } - } + updateTombo.especie_id = alteracao.especie_id; + nomesCientificosPartes.push(especie.nome); - if (alteracao.data_coleta) { - if (alteracao.data_coleta.dia) { - alteracao.data_coleta_dia = alteracao.data_coleta.dia; - } - if (alteracao.data_coleta.mes) { - alteracao.data_coleta_mes = alteracao.data_coleta.mes; - } - if (alteracao.data_coleta.ano) { - alteracao.data_coleta_ano = alteracao.data_coleta.ano; - } - } + updateTombo.sub_especie_id = null; + updateTombo.variedade_id = null; + } - if (alteracao.cidade_id || alteracao.complemento || alteracao.solo_id || alteracao.descricao || alteracao.relevo_id - || alteracao.vegetacao_id || alteracao.fase_sucessional_id) { - const tomboColetaAlteracao = {}; + if (alteracao.sub_especie_id) { + const subespecie = await Subespecie.findOne({ + where: { + id: alteracao.sub_especie_id, + especie_id: updateTombo.especie_id || tomboAtual.especie_id, + }, + transaction, + raw: true, + nest: true, + }); - if (alteracao.cidade_id) { - tomboColetaAlteracao.cidade_id = alteracao.cidade_id; - } + if (!subespecie) { + throw new BadRequestExeption(404); + } - if (alteracao.complemento) { - tomboColetaAlteracao.complemento = alteracao.complemento; - } + updateTombo.sub_especie_id = alteracao.sub_especie_id; + nomesCientificosPartes.push(subespecie.nome); - if (alteracao.solo_id) { - tomboColetaAlteracao.solo_id = alteracao.solo_id; - } + updateTombo.variedade_id = null; + } - if (alteracao.descricao) { - tomboColetaAlteracao.descricao = alteracao.descricao; - } + if (alteracao.variedade_id) { + const variedade = await Variedade.findOne({ + where: { + id: alteracao.variedade_id, + especie_id: updateTombo.especie_id || tomboAtual.especie_id, + }, + transaction, + raw: true, + nest: true, + }); - if (alteracao.relevo_id) { - tomboColetaAlteracao.relevo_id = alteracao.relevo_id; - } + if (!variedade) { + throw new BadRequestExeption(404); + } - if (alteracao.vegetacao_id) { - tomboColetaAlteracao.vegetacao_id = alteracao.vegetacao_id; - } + updateTombo.variedade_id = alteracao.variedade_id; + nomesCientificosPartes.push(variedade.nome); + } - if (alteracao.fase_sucessional_id) { - tomboColetaAlteracao.fase_sucessional_id = alteracao.fase_sucessional_id; - } + if (nomesCientificosPartes.length > 0) { + updateTombo.nome_cientifico = nomesCientificosPartes.join(' '); + } - Tombo.findOne({ - where: { - hcf, - ativo: true, - }, - }).then(tombo => { - LocalColeta.update(tomboColetaAlteracao, { - where: { - id: tombo.dataValues.local_coleta_id, - }, - }); - }); - } + if (alteracao.local_coleta_id) { + const localColeta = await LocalColeta.findOne({ + where: { id: alteracao.local_coleta_id }, + transaction, + raw: true, + nest: true, + }); - if (alteracao.coletores) { - for (let i = 0; i < alteracao.coletores.length; i += 1) { - TomboColetor.findOrCreate({ - where: { - tombo_hcf: hcf, - coletor_id: alteracao.coletores[i], - }, - }).spread((userResult, created) => { - // userResult is the user instance + if (!localColeta) { + throw new BadRequestExeption(404); + } - if (created) { - console.warn(userResult); - } - }); - } - } + updateTombo.local_coleta_id = alteracao.local_coleta_id; + } - if (alteracao.colecoes_anexas_tipo || alteracao.colecoes_anexas_observacoes) { - const colecoesObjeto = {}; + if (alteracao.descricao !== undefined) { + updateTombo.descricao = alteracao.descricao; + } - if (alteracao.colecoes_anexas_tipo) { - colecoesObjeto.tipo = alteracao.colecoes_anexas_tipo; - } + if (alteracao.solo_id) { + const solo = await Solo.findOne({ + where: { id: alteracao.solo_id }, + transaction, + raw: true, + nest: true, + }); - if (alteracao.colecoes_anexas_observacoes) { - colecoesObjeto.observacoes = alteracao.colecoes_anexas_observacoes; - } - Tombo.findOne({ - where: { - hcf, - }, - }).then(tombo => { - ColecaoAnexa.update(colecoesObjeto, { - where: { - id: tombo.dataValues.colecao_anexa_id, - }, - }); - }); - } + if (!solo) { + throw new BadRequestExeption(404); + } - if (alteracao.identificadores || alteracao.data_identificacao) { - const identificadoresObjeto = {}; + updateTombo.solo_id = alteracao.solo_id; + } - if (alteracao.data_identificacao) { - if (alteracao.data_identificacao.dia) { - identificadoresObjeto.data_identificacao_dia = alteracao.data_identificacao.dia; - } + if (alteracao.relevo_id) { + const relevo = await Relevo.findOne({ + where: { id: alteracao.relevo_id }, + transaction, + raw: true, + nest: true, + }); - if (alteracao.data_identificacao.mes) { - identificadoresObjeto.data_identificacao_mes = alteracao.data_identificacao.mes; - } + if (!relevo) { + throw new BadRequestExeption(404); + } - if (alteracao.data_identificacao.ano) { - identificadoresObjeto.data_identificacao_ano = alteracao.data_identificacao.ano; - } - } - Alteracao.update(identificadoresObjeto, { - where: { - tombo_hcf: hcf, - }, - }); - } - Tombo.update(alteracao, { - where: { - hcf, - ativo: true, - }, - }).then(updateResponse => { - response.status(codigos.BUSCAR_UM_ITEM) - .json(updateResponse); - }) - .catch(next); + updateTombo.relevo_id = alteracao.relevo_id; + } + + if (alteracao.vegetacao_id) { + const vegetacao = await Vegetacao.findOne({ + where: { id: alteracao.vegetacao_id }, + transaction, + raw: true, + nest: true, }); - // ); -}; + if (!vegetacao) { + throw new BadRequestExeption(404); + } -export const aprovarComJsonId = (alteracao, hcf, transaction) => { - const parametros = {}; + updateTombo.vegetacao_id = alteracao.vegetacao_id; + } - return Tombo.findOne({ - where: { - hcf, - }, - transaction, - }) - .then(tombo => { - parametros.tombo = tombo; - }) - .then(() => { - if (alteracao.genero_nome) { - return Genero.findOrCreate({ - where: { - nome: alteracao.genero_nome, - }, - defaults: { - nome: alteracao.genero_nome, - familia_id: parametros.tombo.dataValues.familia_id, - ativo: true, - }, - attributes: ['id', 'nome'], - transaction, - }) - .then(([genero]) => { - parametros.genero = genero; - }); - } - return undefined; - }) - .then(() => { - if (alteracao.especie_nome) { - const iniciais = alteracao.autor.match(/([A-Z])/g).join('.'); - return Autor.findOrCreate({ - where: { - nome: alteracao.autor, - }, - defaults: { - nome: alteracao.autor, - iniciais, - ativo: true, - }, - attributes: ['id', 'nome', 'iniciais'], - transaction, - }) - .then(([autor]) => Especie.findOrCreate({ - where: { - nome: alteracao.especie_nome, - }, - defaults: { - nome: alteracao.especie_nome, - genero_id: parametros.tombo.dataValues.genero_id, - familia_id: parametros.tombo.dataValues.familia_id, - autor_id: autor.id, - ativo: true, - }, - attributes: ['id', 'nome'], - transaction, - }) - .then(([especie]) => { - parametros.especie = especie; - })); - } - return undefined; - }) - .then(() => { - if (alteracao.subfamilia_nome) { - return Subfamilia.findOne({ - where: { - nome: alteracao.subfamilia_nome, - }, - attributes: ['id', 'nome'], - transaction, - }) - .then(subfamilia => { - parametros.subfamilia = subfamilia; - }); - } - return undefined; - }) - .then(() => { - if (alteracao.subespecie_nome) { - return Subespecie.findOne({ - where: { - nome: alteracao.subespecie_nome, - }, - attributes: ['id', 'nome'], - transaction, - }) - .then(subEspecie => { - parametros.subespecie = subEspecie; - }); - } - return undefined; - }) - .then(() => { - if (alteracao.variedade_nome) { - return Variedade.findOne({ - where: { - nome: alteracao.variedade_nome, - }, - attributes: ['id', 'nome'], - transaction, - }) - .then(variedade => { - parametros.variedade = variedade; - }); - } - return undefined; - }) - .then(() => parametros.tombo.update({ - especie_id: parametros.especie ? parametros.especie.id : parametros.tombo.especie_id, - genero_id: parametros.genero ? parametros.genero.id : parametros.tombo.genero_id, - subfamilia_id: parametros.subfamilia ? parametros.subfamilia.id : parametros.tombo.subfamilia_id, - subespecie_id: parametros.subespecie ? parametros.subespecie.id : parametros.tombo.subespecie_id, - variedade_id: parametros.variedade ? parametros.variedade.id : parametros.tombo.variedade_id, - }, { + if (alteracao.coletor_id) { + const coletor = await Coletor.findOne({ + where: { id: alteracao.coletor_id }, transaction, - })) - .then(() => - Promise.all([ - Genero.findOne({ - where: { - id: parametros.tombo.genero_id, - }, - attributes: ['nome'], - transaction, - }), - Especie.findOne({ - where: { - id: parametros.tombo.especie_id, - }, - attributes: ['nome'], - transaction, - }), - ]) - ) - .then(([genero, especie]) => - parametros.tombo.update({ - nome_cientifico: `${genero.nome} ${especie.nome}`, + raw: true, + nest: true, + }); + + if (!coletor) { + throw new BadRequestExeption(404); + } + + const numeroColeta = updateTombo.numero_coleta; + if (numeroColeta && coletor.numero && coletor.numero < numeroColeta) { + await Coletor.update({ + numero: numeroColeta, }, { + where: { id: alteracao.coletor_id }, transaction, - }) - ); -}; + }); + } -export const aprovarComJsonNome = (alteracao, hcf, transaction) => { - const parametros = {}; + updateTombo.coletor_id = alteracao.coletor_id; + } - return Familia.findOne({ - where: { - nome: { [Op.like]: `%${alteracao.familia_nome}%` }, - }, - transaction, - }) - .then(familia => { - if (familia) { - return familia; - } - return Familia.create({ nome: alteracao.familia_nome }, transaction); - }) - .then(familia => { - if (familia) { - parametros.familia = familia; - } - if (alteracao.subfamilia_nome) { - return Subfamilia.findOne({ - where: { - nome: { [Op.like]: `%${alteracao.subfamilia_nome}%` }, - }, - transaction, - }); - } - return undefined; - }) - .then(subfamilia => { - if (subfamilia) { - parametros.subfamilia = subfamilia; - } else if (alteracao.subfamilia_nome) { - return Subfamilia.create({ nome: alteracao.subfamilia_nome }, transaction); - } - return undefined; - }) - .then(subfamilia => { - if (subfamilia) { - parametros.subfamilia = subfamilia; - } - if (alteracao.genero_nome) { - return Genero.findOne({ - where: { - nome: { [Op.like]: `%${alteracao.genero_nome}%` }, - }, - transaction, - }); - } - return undefined; - }) - .then(genero => { - if (genero) { - parametros.genero = genero; - } else if (alteracao.genero_nome) { - return Genero.create({ - where: { - nome: { [Op.like]: `%${alteracao.genero_nome}%` }, - }, - transaction, - }); - } - return undefined; - }) - .then(genero => { - if (alteracao.genero_nome) { - parametros.genero = genero; - } - if (alteracao.especie_nome) { - return Especie.findOne({ - where: { - nome: { [Op.like]: `%${alteracao.especie_nome}%` }, - }, - transaction, - }); - } - return undefined; - }) - .then(especie => { - if (especie) { - parametros.especie = especie; - } else if (alteracao.especie_nome) { - return Especie.create({ - where: { - nome: { [Op.like]: `%${alteracao.especie_nome}%` }, - }, - transaction, - }); - } - return undefined; - }) - .then(especie => { - if (alteracao.especie_nome) { - parametros.especie = especie; - } - if (alteracao.subespecie_nome) { - return Subespecie.findOne({ - where: { - nome: { [Op.like]: `%${alteracao.subespecie_nome}%` }, - }, - transaction, - }); - } - return undefined; - }) - .then(subspecie => { - if (subspecie) { - parametros.subespecie = subspecie; - } else if (alteracao.subespecie_nome) { - return Subespecie.create({ - where: { - nome: { [Op.like]: `%${alteracao.subespecie_nome}%` }, - }, - transaction, - }); + if (Object.keys(updateTombo).length > 0) { + await Tombo.update(updateTombo, { + where: { hcf }, + transaction, + }); + } + + if (alteracao.identificadores && Array.isArray(alteracao.identificadores)) { + await TomboIdentificador.destroy({ + where: { tombo_hcf: hcf }, + transaction, + }); + + const identificadoresPromises = alteracao.identificadores.map(async (identificadorId, index) => { + const identificador = await Identificador.findOne({ + where: { id: identificadorId }, + transaction, + raw: true, + nest: true, + }); + + if (!identificador) { + throw new BadRequestExeption(404); } - return undefined; - }) - .then(subspecie => { - if (alteracao.subespecie_nome) { - parametros.subespecie = subspecie; + + return TomboIdentificador.create({ + tombo_hcf: hcf, + identificador_id: identificadorId, + ordem: index + 1, + }, { transaction }); + }); + + await Promise.all(identificadoresPromises); + } + + if (alteracao.complementares !== undefined) { + await ColetorComplementar.destroy({ + where: { hcf }, + transaction, + }); + + if (alteracao.complementares) { + await ColetorComplementar.create({ + hcf, + complementares: alteracao.complementares, + }, { transaction }); + } + } + + if (alteracao.colecoes_anexas_tipo !== undefined || alteracao.colecoes_anexas_observacoes !== undefined) { + const tomboAtualizado = await Tombo.findOne({ + where: { hcf }, + transaction, + raw: true, + nest: true, + }); + + if (tomboAtualizado.colecao_anexa_id) { + const updateColecao = {}; + + if (alteracao.colecoes_anexas_tipo !== undefined) { + updateColecao.tipo = alteracao.colecoes_anexas_tipo; } - if (alteracao.variedade_nome) { - return Variedade.findOne({ - where: { - nome: { [Op.like]: `%${alteracao.variedade_nome}%` }, - }, - transaction, - }); + + if (alteracao.colecoes_anexas_observacoes !== undefined) { + updateColecao.observacoes = alteracao.colecoes_anexas_observacoes; } - return undefined; - }) - .then(variedade => { - if (variedade) { - parametros.variedade = variedade; - } else if (alteracao.variedade_nome) { - return Variedade.create({ - where: { - nome: { [Op.like]: `%${alteracao.variedade_nome}%` }, - }, + + if (Object.keys(updateColecao).length > 0) { + await ColecaoAnexa.update(updateColecao, { + where: { id: tomboAtualizado.colecao_anexa_id }, transaction, }); } - return undefined; - }) - .then(variedade => { - if (alteracao.variedade_nome) { - parametros.variedade = variedade; - } - const update = {}; - if (parametros.familia) { - update.familia_id = parametros.familia.id; - update.nome_cientifico = `${parametros.familia.nome} `; - } - if (parametros.subfamilia) { - update.sub_familia_id = parametros.subfamilia.id; - update.nome_cientifico += `${parametros.subfamilia.nome} `; - } - if (parametros.genero) { - update.genero_id = parametros.genero.id; - update.nome_cientifico += `${parametros.genero.nome} `; - } - if (parametros.especie) { - update.especie_id = parametros.especie.id; - update.nome_cientifico += `${parametros.especie.nome} `; - } - if (parametros.subespecie) { - update.sub_especie_id = parametros.subespecie.id; - update.nome_cientifico += `${parametros.subespecie.nome} `; - } - if (parametros.variedade) { - update.variedade_id = parametros.variedade.id; - update.nome_cientifico += `${parametros.variedade.nome}`; - } - return Tombo.update(update, { - where: { - hcf, - ativo: true, - }, + } else if (alteracao.colecoes_anexas_tipo || alteracao.colecoes_anexas_observacoes) { + const novaColecao = await ColecaoAnexa.create({ + tipo: alteracao.colecoes_anexas_tipo, + observacoes: alteracao.colecoes_anexas_observacoes, + }, { transaction }); + + await Tombo.update({ + colecao_anexa_id: novaColecao.id, + }, { + where: { hcf }, transaction, }); - }) - .then(() => true); + } + } + + const tomboFinal = await Tombo.findOne({ + where: { hcf, ativo: true }, + transaction, + raw: true, + nest: true, + }); + + return { + success: true, + message: 'Pendência aprovada com sucesso', + tombo: tomboFinal, + }; }; +// ...existing code... + export const visualizarComJsonNome = (alteracao, hcf, transaction) => new Promise((resolve, reject) => { Tombo.findOne({ where: { @@ -1802,7 +1690,7 @@ export async function visualizar(request, response, next) { const objetoAlterado = JSON.parse(alteracao.tombo_json); const parametros = {}; - + if (objetoAlterado.nomes_populares) parametros.nome_popular = objetoAlterado.nomes_populares; if (objetoAlterado.numero_coleta) parametros.numero_coleta = objetoAlterado.numero_coleta; if (objetoAlterado.data_coleta?.dia) parametros.data_coleta_dia = objetoAlterado.data_coleta.dia; @@ -1810,7 +1698,7 @@ export async function visualizar(request, response, next) { if (objetoAlterado.data_coleta?.ano) parametros.data_coleta_ano = objetoAlterado.data_coleta.ano; if (objetoAlterado.cor) parametros.cor = objetoAlterado.cor; if (objetoAlterado.altitude) parametros.altitude = objetoAlterado.altitude; - if (objetoAlterado.complemento) parametros.complemento = objetoAlterado.complemento; + if (objetoAlterado.local_coleta_id) parametros.local_coleta_id = objetoAlterado.local_coleta_id; if (objetoAlterado.descricao) parametros.descricao = objetoAlterado.descricao; if (objetoAlterado.data_identificacao?.dia) parametros.data_identificacao_dia = objetoAlterado.data_identificacao.dia; if (objetoAlterado.data_identificacao?.mes) parametros.data_identificacao_mes = objetoAlterado.data_identificacao.mes; @@ -1822,6 +1710,11 @@ export async function visualizar(request, response, next) { if (objetoAlterado.genero_nome) parametros.genero = objetoAlterado.genero_nome; if (objetoAlterado.especie_nome) parametros.especie = objetoAlterado.especie_nome; + if (objetoAlterado.familia_id) parametros.familia = await Familia.findOne({ where: { id: objetoAlterado.familia_id }, raw: true, nest: true }); + if (objetoAlterado.subfamilia_id) parametros.subfamilia = await Subfamilia.findOne({ where: { id: objetoAlterado.subfamilia_id }, raw: true, nest: true }); + if (objetoAlterado.genero_id) parametros.genero = await Genero.findOne({ where: { id: objetoAlterado.genero_id }, raw: true, nest: true }); + if (objetoAlterado.especie_id) parametros.especie = await Especie.findOne({ where: { id: objetoAlterado.especie_id }, raw: true, nest: true }); + if (objetoAlterado.identificadores) parametros.identificador = await Usuario.findOne({ where: { id: objetoAlterado.identificadores }, raw: true, nest: true }); if (objetoAlterado.fase_sucessional_id) parametros.faseSucessional = await FaseSucessional.findOne({ where: { numero: objetoAlterado.fase_sucessional_id }, raw: true, nest: true }); if (objetoAlterado.vegetacao_id) parametros.vegetacao = await Vegetacao.findOne({ where: { id: objetoAlterado.vegetacao_id }, raw: true, nest: true }); @@ -1887,51 +1780,71 @@ export async function visualizar(request, response, next) { jsonRetorno.push({ key: '8', campo: 'Localidade cor', antigo: tombo?.cor || '', novo: parametros.cor }); } - if (parametros.familia && (!tombo?.familia?.nome || tombo.familia.nome !== parametros.familia)) { - jsonRetorno.push({ key: '9', campo: 'Família', antigo: tombo?.familia?.nome || '', novo: parametros.familia }); + if (parametros.familia) { + const nomeFamilia = typeof parametros.familia === 'string' ? parametros.familia : parametros.familia.nome; + const idFamilia = typeof parametros.familia === 'string' ? null : parametros.familia.id; + if ((idFamilia && (!tombo?.familia?.id || tombo.familia.id !== idFamilia)) || (typeof parametros.familia === 'string' && tombo.familia.nome !== nomeFamilia)) { + jsonRetorno.push({ key: '9', campo: 'Família', antigo: tombo?.familia?.nome || '', novo: nomeFamilia }); + } } - if (parametros.genero && (!tombo?.genero?.nome || tombo.genero.nome !== parametros.genero)) { - jsonRetorno.push({ key: '10', campo: 'Gênero', antigo: tombo?.genero?.nome || '', novo: parametros.genero }); + if (parametros.genero) { + const nomeGenero = typeof parametros.genero === 'string' ? parametros.genero : parametros.genero.nome; + const idGenero = typeof parametros.genero === 'string' ? null : parametros.genero.id; + if ((idGenero && (!tombo?.genero?.id || tombo.genero.id !== idGenero)) || (typeof parametros.genero === 'string' && tombo.genero.nome !== nomeGenero)) { + jsonRetorno.push({ key: '10', campo: 'Gênero', antigo: tombo?.genero?.nome || '', novo: nomeGenero }); + } } - if (parametros.subfamilia && (!tombo?.sub_familia?.nome || tombo.sub_familia.nome !== parametros.subfamilia)) { - jsonRetorno.push({ key: '11', campo: 'Subfamília', antigo: tombo?.sub_familia?.nome || '', novo: parametros.subfamilia }); + if (parametros.subfamilia) { + const nomeSubfamilia = typeof parametros.subfamilia === 'string' ? parametros.subfamilia : parametros.subfamilia.nome; + const idSubfamilia = typeof parametros.subfamilia === 'string' ? null : parametros.subfamilia.id; + if ((idSubfamilia && (!tombo?.sub_familia?.id || tombo.sub_familia.id !== idSubfamilia)) || (typeof parametros.subfamilia === 'string' && tombo.sub_familia.nome !== nomeSubfamilia)) { + jsonRetorno.push({ key: '11', campo: 'Subfamília', antigo: tombo?.sub_familia?.nome || '', novo: nomeSubfamilia }); + } } - if (parametros.especie && (!tombo?.especy?.nome || tombo.especy.nome !== parametros.especie)) { - jsonRetorno.push({ key: '12', campo: 'Espécie', antigo: tombo?.especy?.nome || '', novo: parametros.especie }); + if (parametros.especie) { + const nomeEspecie = typeof parametros.especie === 'string' ? parametros.especie : parametros.especie.nome; + const idEspecie = typeof parametros.especie === 'string' ? null : parametros.especie.id; + if ((idEspecie && (!tombo?.especy?.id || tombo.especy.id !== idEspecie)) || (typeof parametros.especie === 'string' && tombo.especy.nome !== nomeEspecie)) { + jsonRetorno.push({ key: '12', campo: 'Espécie', antigo: tombo?.especy?.nome || '', novo: nomeEspecie }); + } } if (parametros.subespecie && (!tombo?.sub_especy?.id || tombo.sub_especy.id !== parametros.subespecie.id)) { jsonRetorno.push({ key: '13', campo: 'Subespécie', antigo: tombo?.sub_especy?.nome || '', novo: parametros.subespecie.nome }); } + if (parametros.variedade && (!tombo?.variedade?.id || tombo.variedade.id !== parametros.variedade.id)) { + jsonRetorno.push({ key: '14', campo: 'Variedade', antigo: tombo?.variedade?.nome || '', novo: parametros.variedade.nome }); + } + if (parametros.altitude && tombo?.altitude !== parametros.altitude) { - jsonRetorno.push({ key: '14', campo: 'Altitude', antigo: tombo?.altitude || '', novo: parametros.altitude }); + jsonRetorno.push({ key: '15', campo: 'Altitude', antigo: tombo?.altitude || '', novo: parametros.altitude }); } if (tombo?.locais_coletum) { if (parametros.cidade && (!tombo?.locais_coletum?.cidade?.id || tombo.locais_coletum.cidade.id !== parametros.cidade.id)) { - jsonRetorno.push({ key: '15', campo: 'Cidade', antigo: tombo?.locais_coletum?.cidade?.nome || '', novo: parametros.cidade.nome }); + jsonRetorno.push({ key: '16', campo: 'Cidade', antigo: tombo?.locais_coletum?.cidade?.nome || '', novo: parametros.cidade.nome }); } - if (parametros.complemento && tombo?.locais_coletum?.complemento !== parametros.complemento) { - jsonRetorno.push({ key: '16', campo: 'Complemento', antigo: tombo?.locais_coletum?.complemento || '', novo: parametros.complemento }); + if (parametros.local_coleta_id && tombo?.locais_coletum?.local_coleta_id !== parametros.local_coleta_id) { + jsonRetorno.push({ key: '17', campo: 'Local de Coleta', antigo: tombo?.locais_coletum?.local_coleta_id || '', novo: parametros.local_coleta_id }); } if (parametros.solo && (!tombo?.locais_coletum?.solo?.id || tombo.locais_coletum.solo.id !== parametros.solo.id)) { - jsonRetorno.push({ key: '17', campo: 'Solo', antigo: tombo?.locais_coletum?.solo?.nome || '', novo: parametros.solo.nome }); + jsonRetorno.push({ key: '18', campo: 'Solo', antigo: tombo?.locais_coletum?.solo?.nome || '', novo: parametros.solo.nome }); } if (parametros.descricao && tombo?.locais_coletum?.descricao !== parametros.descricao) { - jsonRetorno.push({ key: '18', campo: 'Descrição do relevo', antigo: tombo?.locais_coletum?.descricao || '', novo: parametros.descricao }); + jsonRetorno.push({ key: '19', campo: 'Descrição do relevo', antigo: tombo?.locais_coletum?.descricao || '', novo: parametros.descricao }); } if (parametros.relevo && (!tombo?.locais_coletum?.relevo?.id || tombo.locais_coletum.relevo.id !== parametros.relevo.id)) { - jsonRetorno.push({ key: '19', campo: 'Relevo', antigo: tombo?.locais_coletum?.relevo?.nome || '', novo: parametros.relevo.nome }); + jsonRetorno.push({ key: '20', campo: 'Relevo', antigo: tombo?.locais_coletum?.relevo?.nome || '', novo: parametros.relevo.nome }); } if (parametros.vegetacao && (!tombo?.locais_coletum?.vegetaco?.id || tombo.locais_coletum.vegetaco.id !== parametros.vegetacao.id)) { - jsonRetorno.push({ key: '20', campo: 'Vegetação', antigo: tombo?.locais_coletum?.vegetaco?.nome || '', novo: parametros.vegetacao.nome }); + jsonRetorno.push({ key: '21', campo: 'Vegetação', antigo: tombo?.locais_coletum?.vegetaco?.nome || '', novo: parametros.vegetacao.nome }); } if (parametros.faseSucessional && (!tombo?.locais_coletum?.fase_sucessional?.numero || tombo.locais_coletum.fase_sucessional.numero !== parametros.faseSucessional.id)) { - jsonRetorno.push({ key: '21', campo: 'Fase sucessional', antigo: tombo?.locais_coletum?.fase_sucessional?.nome || '', novo: parametros.faseSucessional.nome }); + jsonRetorno.push({ key: '22', campo: 'Fase sucessional', antigo: tombo?.locais_coletum?.fase_sucessional?.nome || '', novo: parametros.faseSucessional.nome }); } } @@ -1948,21 +1861,21 @@ export async function visualizar(request, response, next) { if (identificadores?.length) { const identificadorAntigo = identificadores.find(i => i.ordem === 1)?.identificadore; if (identificadorAntigo && identificadorAntigo.identificador_id !== parametros.identificador.id) { - jsonRetorno.push({ key: '22', campo: 'Identificador', antigo: identificadorAntigo.nome, novo: parametros.identificador.nome }); + jsonRetorno.push({ key: '23', campo: 'Identificador', antigo: identificadorAntigo.nome, novo: parametros.identificador.nome }); } } } if (parametros.data_identificacao_dia && tombo?.data_identificacao_dia !== parametros.data_identificacao_dia) { - jsonRetorno.push({ key: '23', campo: 'Data de identificação dia', antigo: tombo?.data_identificacao_dia || '', novo: parametros.data_identificacao_dia }); + jsonRetorno.push({ key: '24', campo: 'Data de identificação dia', antigo: tombo?.data_identificacao_dia || '', novo: parametros.data_identificacao_dia }); } if (parametros.data_identificacao_mes && tombo?.data_identificacao_mes !== parametros.data_identificacao_mes) { - jsonRetorno.push({ key: '24', campo: 'Data de identificação mês', antigo: tombo?.data_identificacao_mes || '', novo: parametros.data_identificacao_mes }); + jsonRetorno.push({ key: '25', campo: 'Data de identificação mês', antigo: tombo?.data_identificacao_mes || '', novo: parametros.data_identificacao_mes }); } if (parametros.data_identificacao_ano && tombo?.data_identificacao_ano !== parametros.data_identificacao_ano) { - jsonRetorno.push({ key: '25', campo: 'Data de identificação ano', antigo: tombo?.data_identificacao_ano || '', novo: parametros.data_identificacao_ano }); + jsonRetorno.push({ key: '26', campo: 'Data de identificação ano', antigo: tombo?.data_identificacao_ano || '', novo: parametros.data_identificacao_ano }); } const jsonRender = { @@ -2002,7 +1915,7 @@ export function aceitarPendencia(request, response, next) { .then(alt => { if (status === 'APROVADO') { const objetoAlterado = JSON.parse(alt.tombo_json); - retorno = aprovarComJsonId(objetoAlterado, alt.tombo_hcf, transaction); + retorno = aprovarPendencia(objetoAlterado, alt.tombo_hcf, transaction); } return retorno; }); diff --git a/src/controllers/taxonomias-controller.js b/src/controllers/taxonomias-controller.js index f5b98502..5672e4b3 100644 --- a/src/controllers/taxonomias-controller.js +++ b/src/controllers/taxonomias-controller.js @@ -1340,13 +1340,14 @@ export const buscarAutores = async (request, response, next) => { const { limite, pagina, offset } = request.paginacao; const { autor } = request.query; + const { orderClause } = request.ordenacao; const where = { ativo: 1 }; if (autor) where.nome = { [Op.like]: `%${autor}%` }; const result = await Autor.findAndCountAll({ attributes: ['id', 'nome', 'iniciais'], - order: [['created_at', 'DESC']], + order: orderClause, limit: limite, offset, where, diff --git a/src/controllers/tombos-controller.js b/src/controllers/tombos-controller.js index b1e50352..d55768f3 100644 --- a/src/controllers/tombos-controller.js +++ b/src/controllers/tombos-controller.js @@ -12,6 +12,7 @@ import { converteInteiroParaRomano } from '../helpers/tombo'; import models from '../models'; import codigos from '../resources/codigos-http'; import verifyRecaptcha from '../utils/verify-recaptcha'; +import { aprovarPendencia } from './pendencias-controller'; const { Solo, Relevo, Cidade, Estado, Vegetacao, FaseSucessional, Pais, Tipo, LocalColeta, Familia, sequelize, @@ -104,22 +105,21 @@ export const cadastro = (request, response, next) => { return undefined; }) .then(() => { - let json = {}; - // /////////CRIA LOCAL DE COLETA//////////// - if (paisagem) { - json = pick(paisagem, ['descricao', 'solo_id', 'relevo_id', 'vegetacao_id', 'fase_sucessional_id']); - } - if (localidade.complemento) { - json.complemento = localidade.complemento; + if (!localidade?.local_coleta_id) { + throw new BadRequestExeption(400); } - json.cidade_id = localidade.cidade_id; - return LocalColeta.create(json, { transaction }); + return LocalColeta.findOne({ + where: { + id: localidade.local_coleta_id, + }, + transaction, + }); }) .then(localColeta => { if (!localColeta) { - throw new BadRequestExeption(400); + throw new BadRequestExeption(533); } - principal.local_coleta_id = localColeta.id; + return undefined; }) // //////////////CRIA COLECOES ANEXAS/////////// .then(() => { @@ -271,11 +271,15 @@ export const cadastro = (request, response, next) => { data_coleta_mes: principal.data_coleta.mes, data_coleta_ano: principal.data_coleta.ano, numero_coleta: principal.numero_coleta, - local_coleta_id: principal.local_coleta_id, + local_coleta_id: localidade.local_coleta_id, cor: principal.cor, coletor_id: coletor, }; + if (paisagem.descricao) { + jsonTombo.descricao = paisagem.descricao; + } + if (observacoes) { jsonTombo.observacao = observacoes; } @@ -444,202 +448,110 @@ function alteracaoIdentificador(request, transaction) { }); } -function alteracaoCuradorouOperador(request, response, next) { +function alteracaoCuradorouOperador(request, response, transaction) { const { body } = request; + const update = {}; const nomePopular = body?.principal?.nome_popular; + if (nomePopular) update.nomes_populares = nomePopular; const entidadeId = body?.principal?.entidade_id; - const numeroColeta = body.principal.numero_coleta; - const dataColeta = body.principal.data_coleta; + if (entidadeId) update.entidade_id = entidadeId; + const numeroColeta = body?.principal?.numero_coleta; + if (numeroColeta) update.numero_coleta = numeroColeta; + const dataColeta = body?.principal?.data_coleta; + if (dataColeta?.dia) update.data_coleta_dia = dataColeta.dia; + if (dataColeta?.mes) update.data_coleta_mes = dataColeta.mes; + if (dataColeta?.ano) update.data_coleta_ano = dataColeta.ano; const tipoId = body?.principal?.tipo_id; - const { cor } = body.principal || null; + if (tipoId) update.tipo_id = tipoId; + const { cor } = body.principal || {}; + if (cor) update.cor = cor; const familiaId = body?.taxonomia?.familia_id; + if (familiaId) update.familia_id = familiaId; const subfamiliaId = body?.taxonomia?.sub_familia_id; + if (subfamiliaId) update.sub_familia_id = subfamiliaId; const generoId = body?.taxonomia?.genero_id; + if (generoId) update.genero_id = generoId; const especieId = body?.taxonomia?.especie_id; + if (especieId) update.especie_id = especieId; const subespecieId = body?.taxonomia?.sub_especie_id; + if (subespecieId) update.sub_especie_id = subespecieId; const variedadeId = body?.taxonomia?.variedade_id; - - const { latitude } = body.localidade || null; - const { longitude } = body.localidade || null; - const { altitude } = body.localidade || null; - const cidadeId = body.localidade.cidade_id; - const { complemento } = body.localidade || null; - + if (variedadeId) update.variedade_id = variedadeId; + + const latitude = body?.localidade?.latitude; + if (latitude) update.latitude = converteParaDecimal(latitude); + const longitude = body?.localidade?.longitude; + if (longitude) update.longitude = converteParaDecimal(longitude); + const altitude = body?.localidade?.altitude; + if (altitude) update.altitude = altitude; + const localColeta = body?.localidade?.local_coleta_id; + if (localColeta) update.local_coleta_id = localColeta; const soloId = body?.paisagem?.solo_id; - const { descricao } = body.paisagem || null; + if (soloId) update.solo_id = soloId; const relevoId = body?.paisagem?.relevo_id; + if (relevoId) update.relevo_id = relevoId; const vegetacaoId = body?.paisagem?.vegetacao_id; - const faseSucessionalId = body?.paisagem.fase_sucessional_id; - - const { identificadores } = body.identificacao || null; + if (vegetacaoId) update.vegetacao_id = vegetacaoId; + const descricao = body?.paisagem?.descricao; + if (descricao) update.descricao = descricao; + const faseSucessionalId = body?.paisagem?.fase_sucessional_id; + if (faseSucessionalId) update.fase_sucessional_id = faseSucessionalId; + + const identificadores = body?.identificacao?.identificadores; + if (identificadores?.length) update.identificadores = identificadores; const dataIdentificacao = body?.identificacao?.data_identificacao; - - const { coletores } = body || null; - const complementares = body?.coletor_complementar?.complementares || null; + if (dataIdentificacao?.dia) update.data_identificacao_dia = dataIdentificacao.dia; + if (dataIdentificacao?.mes) update.data_identificacao_mes = dataIdentificacao.mes; + if (dataIdentificacao?.ano) update.data_identificacao_ano = dataIdentificacao.ano; + + const coletor = body?.coletor; + if (coletor) update.coletor_id = coletor; + const complementares = body?.coletor_complementar?.complementares; + if (complementares) update.complementares = complementares; const colecoesAnexasTipo = body?.colecoes_anexas?.tipo; + if (colecoesAnexasTipo) update.colecoes_anexas_tipo = colecoesAnexasTipo; const colecoesAnexasObservacoes = body?.colecoes_anexas?.observacoes; - - const { observacoes } = body || null; + if (colecoesAnexasObservacoes) update.colecoes_anexas_observacoes = colecoesAnexasObservacoes; + const { observacoes } = body || {}; + if (observacoes) update.observacao = observacoes; const { tombo_id: tomboId } = request.params; - const update = {}; - - if (nomePopular) { - update.nomes_populares = nomePopular; - } - - if (entidadeId) { - update.entidade_id = entidadeId; - } - - if (numeroColeta) { - update.numero_coleta = numeroColeta; - } - if (dataColeta) { - update.data_coleta = dataColeta; - } - - if (tipoId) { - update.tipo_id = tipoId; - } - - if (cor) { - update.cor = cor; - } - - if (familiaId) { - update.familia_id = familiaId; - } - if (subfamiliaId) { - update.sub_familia_id = subfamiliaId; - } - if (generoId) { - update.genero_id = generoId; - } - if (especieId) { - update.especie_id = especieId; - } - if (subespecieId) { - update.sub_especie_id = subespecieId; - } - if (variedadeId) { - update.variedade_id = variedadeId; - } - - if (latitude) { - update.latitude = converteParaDecimal(latitude); - } - - if (longitude) { - update.longitude = converteParaDecimal(longitude); - } - - if (altitude) { - update.altitude = altitude; - } - - if (cidadeId) { - update.cidade_id = cidadeId; - } - - if (complemento) { - update.complemento = complemento; - } - - if (soloId) { - update.solo_id = soloId; - } - - if (descricao) { - update.descricao = descricao; - } - - if (relevoId) { - update.relevo_id = relevoId; - } - - if (vegetacaoId) { - update.vegetacao_id = vegetacaoId; - } - - if (faseSucessionalId) { - update.fase_sucessional_id = faseSucessionalId; - } - - if (identificadores && identificadores.length > 0) { - update.identificadores = identificadores; - } - - if (dataIdentificacao) { - update.data_identificacao = dataIdentificacao; - } - - if (coletores) { - update.coletores = coletores; - } - - if (complementares) { - update.complementares = complementares; - } - - if (colecoesAnexasTipo) { - update.colecoes_anexas_tipo = colecoesAnexasTipo; - } - - if (colecoesAnexasObservacoes) { - update.colecoes_anexas_observacoes = colecoesAnexasObservacoes; - } - - if (observacoes) { - update.observacao = observacoes; - } - - return Promise.resolve() - .then(() => { - - if (request.usuario.tipo_usuario_id === 2) { // OPERADOR - Alteracao.create({ - tombo_hcf: tomboId, - usuario_id: request.usuario.id, - status: 'ESPERANDO', // operador fica em espera e curador APROVADO {ESPERANDO - para nao esquecer} - tombo_json: JSON.stringify(update), - ativo: true, - identificacao: 1, - }).then(tombos => { - response.status(codigos.BUSCAR_UM_ITEM) - .json(tombos); - }) - .catch(next); - } else if (request.usuario.tipo_usuario_id === 1) { // CURADOR - Alteracao.create({ - tombo_hcf: tomboId, - usuario_id: request.usuario.id, - status: 'APROVADO', // operador fica em espera e curador APROVADO {ESPERANDO - para nao esquecer} - tombo_json: JSON.stringify(update), - ativo: true, - identificacao: 1, - }).then(tombos => { - response.status(codigos.BUSCAR_UM_ITEM) - .json(tombos); - }) - .catch(next); + return Alteracao.create({ + tombo_hcf: tomboId, + usuario_id: request.usuario.id, + status: 'ESPERANDO', + tombo_json: JSON.stringify(update), + ativo: true, + identificacao: 1, + }, { transaction }) + .then(alteracaoCriada => { + if (request.usuario.tipo_usuario_id === 1) { + return aprovarPendencia(update, tomboId, transaction) + .then(() => Alteracao.update({ status: 'APROVADO' }, { + where: { id: alteracaoCriada.id }, + transaction, + })) + .then(() => alteracaoCriada.toJSON()); + } if (request.usuario.tipo_usuario_id !== 2) { + throw new BadRequestExeption(421); } + return alteracaoCriada.toJSON(); }); } export function alteracao(request, response, next) { - const callback = transaction => { + return sequelize.transaction(transaction => { if (request.usuario.tipo_usuario_id === 3) { return alteracaoIdentificador(request, transaction); } if (request.usuario.tipo_usuario_id === 1 || request.usuario.tipo_usuario_id === 2) { - return alteracaoCuradorouOperador(request, response, next); + return alteracaoCuradorouOperador(request, response, transaction); } - return Promise.reject(new BadRequestExeption(421)); - }; - sequelize.transaction(callback) + throw new BadRequestExeption(421); + + }) .then(() => { if (request.usuario.tipo_usuario_id === 3) { response.status(codigos.EDITAR_SEM_RETORNO).send(); @@ -1022,8 +934,6 @@ export const obterTombo = async (request, response, next) => { let resposta = {}; let dadosTombo = {}; - // eslint-disable-next-line - // console.error(id); Promise.resolve() .then(() => Tombo.findOne({ @@ -1052,6 +962,7 @@ export const obterTombo = async (request, response, next) => { 'data_identificacao_dia', 'data_identificacao_mes', 'data_identificacao_ano', + 'descricao', ], include: [ { @@ -1182,27 +1093,20 @@ export const obterTombo = async (request, response, next) => { especieInicial: tombo.especy !== null ? tombo.especy?.id : '', subespecieInicial: tombo.sub_especy !== null ? tombo.sub_especy?.id : '', variedadeInicial: tombo.variedade !== null ? tombo.variedade?.id : '', + idSoloInicial: tombo.solo !== null ? tombo.solo?.id : '', soloInicial: tombo.solo !== null ? tombo.solo?.nome : '', + idRelevoInicial: tombo.relevo !== null ? tombo.relevo?.id : '', relevoInicial: tombo.relevo !== null ? tombo.relevo?.nome : '', + idVegetacaoInicial: tombo.vegetaco !== null ? tombo.vegetaco?.id : '', vegetacaoInicial: tombo.vegetaco !== null ? tombo.vegetaco?.nome : '', faseInicial: tombo.locais_coletum !== null && tombo.locais_coletum?.fase_sucessional !== null ? tombo.locais_coletum?.fase_sucessional?.numero : '', - // coletoresInicial: tombo.coletores.map((coletor) => ({ - // key: `${coletor.id}`, - // label: coletor.nome, - // })), coletor: tombo.coletore ? { id: tombo.coletore?.id, nome: tombo.coletore?.nome, } : null, - // coletorComplementar: tombo.coletorComplementar - // ? { - // hcf: tombo.coletorComplementar.hcf, - // complementares: tombo.coletorComplementar.complementares, - // } - // : '', colecaoInicial: tombo.colecoes_anexa !== null ? tombo.colecoes_anexa?.tipo : '', complementoInicial: tombo.localizacao !== null && tombo.localizacao !== undefined ? tombo.localizacao?.complemento : '', hcf: tombo.hcf, @@ -1211,6 +1115,7 @@ export const obterTombo = async (request, response, next) => { observacao: tombo.observacao !== null ? tombo.observacao : '', tipo: tombo.tipo !== null ? tombo.tipo?.nome : '', numero_coleta: tombo.numero_coleta, + descricao: tombo.descricao !== null ? tombo.descricao : '', herbario: tombo.herbario !== null ? `${tombo.herbario?.sigla} - ${tombo.herbario?.nome}` : '', localizacao: { latitude: tombo.latitude !== null ? tombo.latitude : '', @@ -1231,6 +1136,7 @@ export const obterTombo = async (request, response, next) => { complemento: tombo.locais_coletum?.complemento !== null ? tombo.locais_coletum?.complemento : '', }, local_coleta: { + id: tombo.locais_coletum !== null ? tombo.locais_coletum?.id : '', descricao: tombo.locais_coletum !== null && tombo.locais_coletum?.descricao !== null ? tombo.locais_coletum.descricao : '', solo: tombo.solo !== null ? tombo.solo?.nome : '', relevo: tombo.relevo !== null ? tombo.relevo?.nome : '', diff --git a/src/database/cli.ts b/src/database/cli.ts index 033fcff4..1e23d50f 100644 --- a/src/database/cli.ts +++ b/src/database/cli.ts @@ -27,7 +27,7 @@ const migrationKnex = createKnex({ } }) -const migrationFileSystem = new MigrationFileSystem({ knex: migrationKnex, migrationsPath: path.join(__dirname, 'migrations') }) +const migrationFileSystem = new MigrationFileSystem({ knex: migrationKnex, migrationsPath: path.join(__dirname, 'migration') }) const migrationDataSource = new MigrationRepository({ knex: migrationKnex, tableName: 'migrations' }) async function createMigration(name: string) { diff --git a/src/models/Tombo.js b/src/models/Tombo.js index 44ac13ad..0759eadb 100644 --- a/src/models/Tombo.js +++ b/src/models/Tombo.js @@ -261,6 +261,10 @@ export default (Sequelize, DataTypes) => { type: DataTypes.INTEGER, allowNull: true, }, + descricao: { + type: DataTypes.TEXT, + allowNull: true, + }, }; const options = { diff --git a/src/resources/errors/500-taxonomias.js b/src/resources/errors/500-taxonomias.js index 21df4ab2..9c5705bb 100644 --- a/src/resources/errors/500-taxonomias.js +++ b/src/resources/errors/500-taxonomias.js @@ -31,4 +31,5 @@ export default { 530: 'Vegetação não encontrada.', 531: 'Fase sucessional não encontrada.', 532: 'Autor não encontrado.', + 533: 'Local de coleta não encontrado.', }; diff --git a/src/routes/locais.js b/src/routes/locais.js index 0e5fa934..3a535c21 100644 --- a/src/routes/locais.js +++ b/src/routes/locais.js @@ -1,5 +1,8 @@ +import listagensMiddleware from '../middlewares/listagens-middleware'; import tokensMiddleware, { TIPOS_USUARIOS } from '../middlewares/tokens-middleware'; import validacoesMiddleware from '../middlewares/validacoes-middleware'; +import localColetaCadastroEsquema from '../validators/localColeta-cadastro'; +import localColetaListagemEsquema from '../validators/localColeta-listagem'; import nomeEsquema from '../validators/nome-obrigatorio'; const controller = require('../controllers/locais-coleta-controller'); @@ -233,4 +236,289 @@ export default app => { .get([ controller.buscarVegetacoes, ]); + + /** + * @swagger + * /locais-coleta: + * post: + * summary: Cadastra um novo local de coleta + * tags: [Locais] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * descricao: + * type: string + * complemento: + * type: string + * cidade_id: + * type: integer + * fase_sucessional_id: + * type: integer + * required: + * - descricao + * - cidade_id + * example: + * descricao: "Próximo ao rio" + * complemento: "Entrada pela fazenda" + * cidade_id: 1 + * fase_sucessional_id: 2 + * responses: + * 201: + * description: Local de coleta cadastrado com sucesso + * '400': + * $ref: '#/components/responses/BadRequest' + * '401': + * $ref: '#/components/responses/Unauthorized' + * '403': + * $ref: '#/components/responses/Forbidden' + */ + app.route('/locais-coleta') + .post([ + tokensMiddleware([ + TIPOS_USUARIOS.CURADOR, + TIPOS_USUARIOS.OPERADOR, + ]), + validacoesMiddleware(localColetaCadastroEsquema), + controller.cadastrarLocalColeta, + ]) + /** + * @swagger + * /locais-coleta: + * get: + * summary: Lista os locais de coleta + * tags: [Locais] + * parameters: + * - in: query + * name: cidadeId + * schema: + * type: integer + * description: Filtrar por ID da cidade + * - in: query + * name: pagina + * schema: + * type: integer + * description: Número da página + * - in: query + * name: limite + * schema: + * type: integer + * description: Quantidade de resultados por página + * responses: + * 200: + * description: Lista de locais de coleta + * content: + * application/json: + * schema: + * type: object + * properties: + * metadados: + * type: object + * locaisColeta: + * type: array + * items: + * type: object + * '401': + * $ref: '#/components/responses/Unauthorized' + * '403': + * $ref: '#/components/responses/Forbidden' + */ + .get([ + tokensMiddleware([ + TIPOS_USUARIOS.CURADOR, + TIPOS_USUARIOS.OPERADOR, + TIPOS_USUARIOS.IDENTIFICADOR, + ]), + listagensMiddleware, + validacoesMiddleware(localColetaListagemEsquema), + controller.buscarLocaisColeta, + ]); + /** + * @swagger + * /locais-coleta/{id}: + * get: + * summary: Busca um local de coleta pelo ID + * tags: [Locais] + * description: Retorna os dados de um local de coleta específico. + * parameters: + * - in: path + * name: id + * required: true + * schema: + * type: integer + * description: ID do local de coleta + * responses: + * 200: + * description: Dados do local de coleta encontrados + * content: + * application/json: + * schema: + * type: object + * properties: + * id: + * type: integer + * descricao: + * type: string + * complemento: + * type: string + * nullable: true + * cidade_id: + * type: integer + * fase_sucessional_id: + * type: integer + * nullable: true + * cidade: + * type: object + * properties: + * id: + * type: integer + * nome: + * type: string + * fase_sucessional: + * type: object + * nullable: true + * properties: + * id: + * type: integer + * nome: + * type: string + * '401': + * $ref: '#/components/responses/Unauthorized' + * '403': + * $ref: '#/components/responses/Forbidden' + * '404': + * $ref: '#/components/responses/NotFound' + * '500': + * $ref: '#/components/responses/InternalServerError' + * put: + * summary: Atualiza um local de coleta + * tags: [Locais] + * description: Atualiza os dados de um local de coleta existente. + * parameters: + * - in: path + * name: id + * required: true + * schema: + * type: integer + * description: ID do local de coleta + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * descricao: + * type: string + * description: Descrição do local de coleta + * complemento: + * type: string + * description: Complemento do local de coleta + * cidade_id: + * type: integer + * description: ID da cidade + * fase_sucessional_id: + * type: integer + * description: ID da fase sucessional + * required: + * - descricao + * - cidade_id + * example: + * descricao: "Próximo ao córrego" + * complemento: "Entrada pelo portão principal" + * cidade_id: 2 + * fase_sucessional_id: 3 + * responses: + * 200: + * description: Local de coleta atualizado com sucesso + * content: + * application/json: + * schema: + * type: object + * properties: + * id: + * type: integer + * descricao: + * type: string + * complemento: + * type: string + * cidade_id: + * type: integer + * fase_sucessional_id: + * type: integer + * '400': + * $ref: '#/components/responses/BadRequest' + * '401': + * $ref: '#/components/responses/Unauthorized' + * '403': + * $ref: '#/components/responses/Forbidden' + * '404': + * $ref: '#/components/responses/NotFound' + * '500': + * $ref: '#/components/responses/InternalServerError' + */ + app.route('/locais-coleta/:id') + .get([ + tokensMiddleware([ + TIPOS_USUARIOS.CURADOR, + TIPOS_USUARIOS.OPERADOR, + TIPOS_USUARIOS.IDENTIFICADOR, + ]), + controller.buscarLocalColetaPorId, + ]) + .put([ + tokensMiddleware([ + TIPOS_USUARIOS.CURADOR, + TIPOS_USUARIOS.OPERADOR, + ]), + validacoesMiddleware(localColetaCadastroEsquema), + controller.atualizarLocalColeta, + ]) + /** + * @swagger + * /locais-coleta/{id}: + * delete: + * summary: Remove um local de coleta + * tags: [Locais] + * description: Remove um local de coleta pelo ID. Verifica se não há tombos associados antes de remover. + * parameters: + * - in: path + * name: id + * required: true + * schema: + * type: integer + * description: ID do local de coleta + * responses: + * 204: + * description: Local de coleta removido com sucesso + * '400': + * description: Não é possível excluir - existem tombos associados + * content: + * application/json: + * schema: + * type: object + * properties: + * mensagem: + * type: string + * example: + * mensagem: "Não é possível excluir o local de coleta. Existem 5 tombo(s) associado(s) a este local." + * '401': + * $ref: '#/components/responses/Unauthorized' + * '403': + * $ref: '#/components/responses/Forbidden' + * '404': + * $ref: '#/components/responses/NotFound' + * '500': + * $ref: '#/components/responses/InternalServerError' + */ + .delete([ + tokensMiddleware([ + TIPOS_USUARIOS.CURADOR, + TIPOS_USUARIOS.OPERADOR, + ]), + controller.deletarLocalColeta, + ]); }; diff --git a/src/routes/taxonomias.js b/src/routes/taxonomias.js index e082899e..d078016f 100644 --- a/src/routes/taxonomias.js +++ b/src/routes/taxonomias.js @@ -39,6 +39,7 @@ const generosOrdenacaoMiddleware = criaOrdenacaoMiddleware(['genero', 'familia', const especiesOrdenacaoMiddleware = criaOrdenacaoMiddleware(['especie', 'reino', 'familia', 'genero', 'familia'], 'nome', 'asc'); const subEspeciesOrdenacaoMiddleware = criaOrdenacaoMiddleware(['subespecie', 'reino', 'familia', 'genero', 'especie', 'autor'], 'nome', 'asc'); const variedadesOrdenacaoMiddleware = criaOrdenacaoMiddleware(['variedade', 'reino', 'familia', 'genero', 'especie', 'autor'], 'nome', 'asc'); +const autorOrdenacaoMiddleware = criaOrdenacaoMiddleware(['autor', 'iniciais'], 'nome', 'asc'); /** * @swagger @@ -1622,6 +1623,7 @@ export default app => { ]) .get([ listagensMiddleware, + autorOrdenacaoMiddleware, validacoesMiddleware(autorListagemEsquema), controller.buscarAutores, ]); diff --git a/src/validators/localColeta-cadastro.js b/src/validators/localColeta-cadastro.js new file mode 100644 index 00000000..6f1c8530 --- /dev/null +++ b/src/validators/localColeta-cadastro.js @@ -0,0 +1,25 @@ +export default { + descricao: { + in: ['body'], + isString: true, + notEmpty: true, + errorMessage: 'Descrição é obrigatória.', + }, + complemento: { + in: ['body'], + isString: true, + optional: true, + }, + cidade_id: { + in: ['body'], + isInt: true, + notEmpty: true, + errorMessage: 'ID da cidade é obrigatório e deve ser um número inteiro.', + }, + fase_sucessional_id: { + in: ['body'], + isInt: true, + optional: true, + errorMessage: 'ID da fase sucessional deve ser um número inteiro.', + }, +}; diff --git a/src/validators/localColeta-listagem.js b/src/validators/localColeta-listagem.js new file mode 100644 index 00000000..9a19683e --- /dev/null +++ b/src/validators/localColeta-listagem.js @@ -0,0 +1,8 @@ +export default { + cidade_id: { + in: ['query'], + isInt: true, + optional: true, + errorMessage: 'ID da cidade deve ser um número inteiro.', + }, +}; diff --git a/src/validators/tombo-alteracao.js b/src/validators/tombo-alteracao.js index 008838cc..6cc7ae53 100644 --- a/src/validators/tombo-alteracao.js +++ b/src/validators/tombo-alteracao.js @@ -98,7 +98,7 @@ export default { isEmpty: false, isInt: true, }, - 'json.localidade.complemento': { + 'json.localidade.local_coleta_id': { in: 'body', isString: true, isEmpty: false, diff --git a/src/validators/tombo-cadastro.js b/src/validators/tombo-cadastro.js index 487362b4..ed0510f6 100644 --- a/src/validators/tombo-cadastro.js +++ b/src/validators/tombo-cadastro.js @@ -106,13 +106,10 @@ export default { isEmpty: false, isInt: true, }, - 'json.localidade.complemento': { + 'json.localidade.local_coleta_id': { in: 'body', - isString: true, - optional: true, - isLength: { - options: [{ min: 3 }], - }, + isInt: true, + isEmpty: false, }, 'json.paisagem.solo_id': { in: 'body', diff --git a/src/views/ficha-tombo.ejs b/src/views/ficha-tombo.ejs index 2e4a44be..ea0344d1 100644 --- a/src/views/ficha-tombo.ejs +++ b/src/views/ficha-tombo.ejs @@ -228,7 +228,7 @@