diff --git a/Orius Mirror.postman_collection.json b/Orius Mirror.postman_collection.json new file mode 100644 index 0000000..3856050 --- /dev/null +++ b/Orius Mirror.postman_collection.json @@ -0,0 +1,1410 @@ +{ + "info": { + "_postman_id": "c127ccdc-0035-4608-98a0-6589732bb931", + "name": "Orius Mirror", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "32142370" + }, + "item": [ + { + "name": "Usuarios", + "item": [ + { + "name": "Autenticar", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "const response = pm.response.json();\r", + "\r", + "// Salvando em variáveis da *collection*\r", + "pm.collectionVariables.set(\"BearerToken\", response.data.token);\r", + "\r", + "pm.test(\"Status code é 201 ou 200\", function () {\r", + " pm.expect(pm.response.code).to.be.oneOf([200, 201]);\r", + "});\r", + "\r", + "pm.test(\"Resposta contém ID ou confirmação\", function () {\r", + " const jsonData = pm.response.json();\r", + " pm.expect(jsonData).to.have.any.keys(\"id\", \"message\", \"status\");\r", + "});\r", + "\r", + "pm.test(\"Mensagem indica sucesso\", function () {\r", + " const jsonData = pm.response.json();\r", + " pm.expect(jsonData.message || \"\").to.match(/sucesso|criado|registrado/i);\r", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"username\": \"orius\",\r\n \"password\": \"123123\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/usuario/authenticate", + "host": [ + "{{url}}" + ], + "path": [ + "usuario", + "authenticate" + ] + } + }, + "response": [] + }, + { + "name": "Usuário logado", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BearerToken}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/usuario/me", + "host": [ + "{{url}}" + ], + "path": [ + "usuario", + "me" + ] + } + }, + "response": [] + }, + { + "name": "Localizar e-mail", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BearerToken}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/usuario/email/dev@oriustecnologia.com.br", + "host": [ + "{{url}}" + ], + "path": [ + "usuario", + "email", + "dev@oriustecnologia.com.br" + ] + } + }, + "response": [] + }, + { + "name": "Localizar ID", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BearerToken}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/usuario/1", + "host": [ + "{{url}}" + ], + "path": [ + "usuario", + "1" + ] + } + }, + "response": [] + }, + { + "name": "Listagem", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BearerToken}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/usuario/", + "host": [ + "{{url}}" + ], + "path": [ + "usuario", + "" + ] + } + }, + "response": [] + }, + { + "name": "Cadastrar", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BearerToken}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"nome\": \"{{$randomFullName}}\",\r\n \"email\": \"{{$randomEmail}}\",\r\n \"username\": \"{{$randomUserName}}\",\r\n \"password\": \"{{$randomPassword}}\",\r\n \"status\": \"A\",\r\n \"user_id_create\": 1\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/usuario/", + "host": [ + "{{url}}" + ], + "path": [ + "usuario", + "" + ] + } + }, + "response": [] + }, + { + "name": "Atualizar", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BearerToken}}", + "type": "string" + } + ] + }, + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"nome\": \"{{$randomFullName}}\",\r\n \"email\": \"{{$randomEmail}}\",\r\n \"username\": \"{{$randomUserName}}\",\r\n \"password\": \"{{$randomPassword}}\",\r\n \"status\": \"A\",\r\n \"user_id_update\": 1\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/usuario/18", + "host": [ + "{{url}}" + ], + "path": [ + "usuario", + "18" + ] + } + }, + "response": [] + }, + { + "name": "Deletar", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BearerToken}}", + "type": "string" + } + ] + }, + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/usuario/3", + "host": [ + "{{url}}" + ], + "path": [ + "usuario", + "3" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Ato Documento", + "item": [ + { + "name": "Listagem", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BearerToken}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/ato_documento/", + "host": [ + "{{url}}" + ], + "path": [ + "ato_documento", + "" + ] + } + }, + "response": [] + }, + { + "name": "Cadastrar", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BearerToken}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"ato_principal_id\": 1,\r\n \"url\": \"https://google.com\",\r\n \"nome_documento\": \"{{$randomFullName}}\",\r\n \"tipo_documento\": \"ESCRITURA COMPRA E VENDA\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/ato_documento/", + "host": [ + "{{url}}" + ], + "path": [ + "ato_documento", + "" + ] + } + }, + "response": [] + }, + { + "name": "Atualizar", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BearerToken}}", + "type": "string" + } + ] + }, + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"ato_principal_id\": 1,\r\n \"url\": \"https://google.com\",\r\n \"nome_documento\": \"{{$randomFullName}}\",\r\n \"tipo_documento\": \"PDF\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/ato_documento/12", + "host": [ + "{{url}}" + ], + "path": [ + "ato_documento", + "12" + ] + } + }, + "response": [] + }, + { + "name": "Localizar Ato Principal", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BearerToken}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/ato_documento/ato_principal/1", + "host": [ + "{{url}}" + ], + "path": [ + "ato_documento", + "ato_principal", + "1" + ] + } + }, + "response": [] + }, + { + "name": "Localizar ID", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BearerToken}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/ato_documento/3", + "host": [ + "{{url}}" + ], + "path": [ + "ato_documento", + "3" + ] + } + }, + "response": [] + }, + { + "name": "Deletar", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BearerToken}}", + "type": "string" + } + ] + }, + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/ato_documento/7", + "host": [ + "{{url}}" + ], + "path": [ + "ato_documento", + "7" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Ato Parte", + "item": [ + { + "name": "Listagem", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BearerToken}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/ato_parte/", + "host": [ + "{{url}}" + ], + "path": [ + "ato_parte", + "" + ] + } + }, + "response": [] + }, + { + "name": "Cadastrar", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BearerToken}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"ato_principal_id\": 1,\r\n \"nome\": \"{{$randomFullName}}\",\r\n \"cpf_cnpj\": \"11352091038\",\r\n \"telefone\": \"{{$randomPhoneNumber}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/ato_parte/", + "host": [ + "{{url}}" + ], + "path": [ + "ato_parte", + "" + ] + } + }, + "response": [] + }, + { + "name": "Atualizar", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BearerToken}}", + "type": "string" + } + ] + }, + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"ato_principal_id\": 1,\r\n \"nome\": \"{{$randomFullName}}\",\r\n \"cpf_cnpj\": \"11352091038\",\r\n \"telefone\": \"{{$randomAlphaNumeric}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/ato_parte/16", + "host": [ + "{{url}}" + ], + "path": [ + "ato_parte", + "16" + ] + } + }, + "response": [] + }, + { + "name": "Localizar Ato Principal", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BearerToken}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/ato_parte/ato_principal/1", + "host": [ + "{{url}}" + ], + "path": [ + "ato_parte", + "ato_principal", + "1" + ] + } + }, + "response": [] + }, + { + "name": "Localizar ID", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BearerToken}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/ato_parte/11", + "host": [ + "{{url}}" + ], + "path": [ + "ato_parte", + "11" + ] + } + }, + "response": [] + }, + { + "name": "Deletar", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BearerToken}}", + "type": "string" + } + ] + }, + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/ato_parte/2", + "host": [ + "{{url}}" + ], + "path": [ + "ato_parte", + "2" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Ato Principal", + "item": [ + { + "name": "Listagem", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BearerToken}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/ato/", + "host": [ + "{{url}}" + ], + "path": [ + "ato", + "" + ] + } + }, + "response": [] + }, + { + "name": "Cadastrar", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BearerToken}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"identificacao_pedido_cgj\": {{randomNumber}},\r\n \"tipo_ato\": {{randomNumber}},\r\n \"codigo_selo\": \"{{$randomAlphaNumeric}}{{$randomAlphaNumeric}}\",\r\n \"codigo_ato\": \"{{$randomAlphaNumeric}}{{randomNumber}}\",\r\n \"nome_civil_ato\": \"{{$randomFullName}}\",\r\n \"nome_serventuario_praticou_ato\": \"{{$randomFullName}}\",\r\n \"data_solicitacao\": \"2025-10-21 15:30:00\",\r\n \"ip_maquina\": \"{{$randomIP}}\",\r\n \"inteiro_teor\": \"Texto do inteiro teor\",\r\n \"valor_entrada\": {{$randomPrice}},\r\n \"emolumento\": {{$randomPrice}},\r\n \"taxa_judiciaria\": {{$randomPrice}},\r\n \"fundos_estaduais\": {{$randomPrice}},\r\n \"protocolo_protesto\": \"PROT-2025-{{randomNumber}}\",\r\n \"protocolo_imovel\": \"IMOV-2025-{{randomNumber}}\"\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/ato/", + "host": [ + "{{url}}" + ], + "path": [ + "ato", + "" + ] + } + }, + "response": [] + }, + { + "name": "Cadastrar Multiplos", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BearerToken}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "[\r\n {\r\n \"identificacao_pedido_cgj\": {{randomNumber}},\r\n \"tipo_ato\": {{randomNumber}},\r\n \"codigo_selo\": \"{{$randomColor}}{{$randomAlphaNumeric}}{{$randomAlphaNumeric}}\",\r\n \"codigo_ato\": \"{{$randomColor}}{{$randomAlphaNumeric}}{{randomNumber}}\",\r\n \"nome_civil_ato\": \"{{$randomFullName}}\",\r\n \"nome_serventuario_praticou_ato\": \"{{$randomFullName}}\",\r\n \"data_solicitacao\": \"2025-10-21 15:30:00\",\r\n \"ip_maquina\": \"{{$randomIP}}\",\r\n \"inteiro_teor\": \"Texto do inteiro teor\",\r\n \"valor_entrada\": {{$randomPrice}},\r\n \"emolumento\": {{$randomPrice}},\r\n \"taxa_judiciaria\": {{$randomPrice}},\r\n \"fundos_estaduais\": {{$randomPrice}},\r\n \"protocolo_protesto\": \"PROT-2025-{{randomNumber}}\",\r\n \"protocolo_imovel\": \"IMOV-2025-{{randomNumber}}\",\r\n \"atos_vinculados\": [\r\n {\r\n \"identificacao_pedido_cgj\": {{randomNumber}},\r\n \"tipo_ato\": {{randomNumber}},\r\n \"codigo_selo\": \"{{$randomColor}}{{$randomAlphaNumeric}}{{$randomAlphaNumeric}}\",\r\n \"codigo_ato\": \"{{$randomColor}}{{$randomAlphaNumeric}}{{randomNumber}}\",\r\n \"nome_civil_ato\": \"{{$randomFullName}}\",\r\n \"nome_serventuario_praticou_ato\": \"{{$randomFullName}}\",\r\n \"data_solicitacao\": \"2025-10-21 15:30:00\",\r\n \"ip_maquina\": \"{{$randomIP}}\",\r\n \"inteiro_teor\": \"Texto do inteiro teor\",\r\n \"valor_entrada\": {{$randomPrice}},\r\n \"emolumento\": {{$randomPrice}},\r\n \"taxa_judiciaria\": {{$randomPrice}},\r\n \"fundos_estaduais\": {{$randomPrice}},\r\n \"protocolo_protesto\": \"PROT-2025-{{randomNumber}}\",\r\n \"protocolo_imovel\": \"IMOV-2025-{{randomNumber}}\",\r\n \"ato_partes\": [\r\n {\r\n \"nome\": \"{{$randomFullName}}\",\r\n \"telefone\": \"{{$randomPhoneNumber}}\",\r\n \"cpf_cnpj\": \"12345678901\"\r\n },\r\n {\r\n \"nome\": \"{{$randomCompanyName}}\",\r\n \"telefone\": \"{{$randomPhoneNumber}}\",\r\n \"cpf_cnpj\": \"12345678000199\"\r\n }\r\n ],\r\n \"ato_documentos\": [\r\n {\r\n \"url\": \"https://exemplo.com/documentos/ato_2025_0001.pdf\",\r\n \"nome_documento\": \"ATO_2025_0001.pdf\",\r\n \"tipo_documento\": \"ATO_LAVRADO\"\r\n },\r\n {\r\n \"url\": \"https://exemplo.com/documentos/certidao_2025_0001.pdf\",\r\n \"nome_documento\": \"CERTIDAO_2025_0001.pdf\",\r\n \"tipo_documento\": \"CERTIDAO\"\r\n }\r\n ]\r\n\r\n }\r\n\r\n ], \r\n \"ato_partes\": [\r\n {\r\n \"nome\": \"{{$randomCompanyName}}\",\r\n \"telefone\": \"{{$randomPhoneNumber}}\",\r\n \"cpf_cnpj\": \"12345678901\"\r\n },\r\n {\r\n \"nome\": \"{{$randomFullName}}\",\r\n \"telefone\": \"{{$randomPhoneNumber}}\",\r\n \"cpf_cnpj\": \"12345678000199\"\r\n }\r\n ],\r\n \"ato_documentos\": [\r\n {\r\n \"url\": \"https://exemplo.com/documentos/ato_2025_0001.pdf\",\r\n \"nome_documento\": \"ATO_2025_0001.pdf\",\r\n \"tipo_documento\": \"ATO_LAVRADO\"\r\n },\r\n {\r\n \"url\": \"https://exemplo.com/documentos/certidao_2025_0001.pdf\",\r\n \"nome_documento\": \"CERTIDAO_2025_0001.pdf\",\r\n \"tipo_documento\": \"CERTIDAO\"\r\n }\r\n ] \r\n },\r\n {\r\n \"identificacao_pedido_cgj\": {{randomNumber}},\r\n \"tipo_ato\": {{randomNumber}},\r\n \"codigo_selo\": \"{{$randomColor}}{{$randomAlphaNumeric}}{{$randomAlphaNumeric}}\",\r\n \"codigo_ato\": \"{{$randomColor}}{{$randomAlphaNumeric}}{{randomNumber}}\",\r\n \"nome_civil_ato\": \"{{$randomFullName}}\",\r\n \"nome_serventuario_praticou_ato\": \"{{$randomFullName}}\",\r\n \"data_solicitacao\": \"2025-10-21 15:30:00\",\r\n \"ip_maquina\": \"{{$randomIP}}\",\r\n \"inteiro_teor\": \"Texto do inteiro teor\",\r\n \"valor_entrada\": {{$randomPrice}},\r\n \"emolumento\": {{$randomPrice}},\r\n \"taxa_judiciaria\": {{$randomPrice}},\r\n \"fundos_estaduais\": {{$randomPrice}},\r\n \"protocolo_protesto\": \"PROT-2025-{{randomNumber}}\",\r\n \"protocolo_imovel\": \"IMOV-2025-{{randomNumber}}\",\r\n \"atos_vinculados\": [\r\n {\r\n \"identificacao_pedido_cgj\": {{randomNumber}},\r\n \"tipo_ato\": {{randomNumber}},\r\n \"codigo_selo\": \"{{$randomColor}}{{$randomAlphaNumeric}}{{$randomAlphaNumeric}}\",\r\n \"codigo_ato\": \"{{$randomColor}}{{$randomAlphaNumeric}}{{randomNumber}}\",\r\n \"nome_civil_ato\": \"{{$randomFullName}}\",\r\n \"nome_serventuario_praticou_ato\": \"{{$randomFullName}}\",\r\n \"data_solicitacao\": \"2025-10-21 15:30:00\",\r\n \"ip_maquina\": \"{{$randomIP}}\",\r\n \"inteiro_teor\": \"Texto do inteiro teor\",\r\n \"valor_entrada\": {{$randomPrice}},\r\n \"emolumento\": {{$randomPrice}},\r\n \"taxa_judiciaria\": {{$randomPrice}},\r\n \"fundos_estaduais\": {{$randomPrice}},\r\n \"protocolo_protesto\": \"PROT-2025-{{randomNumber}}\",\r\n \"protocolo_imovel\": \"IMOV-2025-{{randomNumber}}\",\r\n \"ato_partes\": [\r\n {\r\n \"nome\": \"{{$randomFullName}}\",\r\n \"telefone\": \"{{$randomPhoneNumber}}\",\r\n \"cpf_cnpj\": \"12345678901\"\r\n },\r\n {\r\n \"nome\": \"{{$randomFullName}}\",\r\n \"telefone\": \"{{$randomPhoneNumber}}\",\r\n \"cpf_cnpj\": \"12345678000199\"\r\n }\r\n ],\r\n \"ato_documentos\": [\r\n {\r\n \"url\": \"https://exemplo.com/documentos/ato_2025_0001.pdf\",\r\n \"nome_documento\": \"ATO_2025_0001.pdf\",\r\n \"tipo_documento\": \"ATO_LAVRADO\"\r\n },\r\n {\r\n \"url\": \"https://exemplo.com/documentos/certidao_2025_0001.pdf\",\r\n \"nome_documento\": \"CERTIDAO_2025_0001.pdf\",\r\n \"tipo_documento\": \"CERTIDAO\"\r\n }\r\n ]\r\n\r\n }\r\n\r\n ], \r\n \"ato_partes\": [\r\n {\r\n \"nome\": \"{{$randomFullName}}\",\r\n \"telefone\": \"{{$randomPhoneNumber}}\",\r\n \"cpf_cnpj\": \"12345678901\"\r\n },\r\n {\r\n \"nome\": \"{{$randomCompanyName}}\",\r\n \"telefone\": \"{{$randomPhoneNumber}}\",\r\n \"cpf_cnpj\": \"12345678000199\"\r\n }\r\n ],\r\n \"ato_documentos\": [\r\n {\r\n \"url\": \"https://exemplo.com/documentos/ato_2025_0001.pdf\",\r\n \"nome_documento\": \"ATO_2025_0001.pdf\",\r\n \"tipo_documento\": \"ATO_LAVRADO\"\r\n },\r\n {\r\n \"url\": \"https://exemplo.com/documentos/certidao_2025_0001.pdf\",\r\n \"nome_documento\": \"CERTIDAO_2025_0001.pdf\",\r\n \"tipo_documento\": \"CERTIDAO\"\r\n }\r\n ] \r\n },\r\n {\r\n \"identificacao_pedido_cgj\": {{randomNumber}},\r\n \"tipo_ato\": {{randomNumber}},\r\n \"codigo_selo\": \"{{$randomColor}}{{$randomAlphaNumeric}}{{$randomAlphaNumeric}}\",\r\n \"codigo_ato\": \"{{$randomColor}}{{$randomAlphaNumeric}}{{randomNumber}}\",\r\n \"nome_civil_ato\": \"{{$randomFullName}}\",\r\n \"nome_serventuario_praticou_ato\": \"{{$randomFullName}}\",\r\n \"data_solicitacao\": \"2025-10-21 15:30:00\",\r\n \"ip_maquina\": \"{{$randomIP}}\",\r\n \"inteiro_teor\": \"Texto do inteiro teor\",\r\n \"valor_entrada\": {{$randomPrice}},\r\n \"emolumento\": {{$randomPrice}},\r\n \"taxa_judiciaria\": {{$randomPrice}},\r\n \"fundos_estaduais\": {{$randomPrice}},\r\n \"protocolo_protesto\": \"PROT-2025-{{randomNumber}}\",\r\n \"protocolo_imovel\": \"IMOV-2025-{{randomNumber}}\",\r\n \"atos_vinculados\": [\r\n {\r\n \"identificacao_pedido_cgj\": {{randomNumber}},\r\n \"tipo_ato\": {{randomNumber}},\r\n \"codigo_selo\": \"{{$randomColor}}{{$randomAlphaNumeric}}{{$randomAlphaNumeric}}\",\r\n \"codigo_ato\": \"{{$randomColor}}{{$randomAlphaNumeric}}{{randomNumber}}\",\r\n \"nome_civil_ato\": \"{{$randomFullName}}\",\r\n \"nome_serventuario_praticou_ato\": \"{{$randomFullName}}\",\r\n \"data_solicitacao\": \"2025-10-21 15:30:00\",\r\n \"ip_maquina\": \"{{$randomIP}}\",\r\n \"inteiro_teor\": \"Texto do inteiro teor\",\r\n \"valor_entrada\": {{$randomPrice}},\r\n \"emolumento\": {{$randomPrice}},\r\n \"taxa_judiciaria\": {{$randomPrice}},\r\n \"fundos_estaduais\": {{$randomPrice}},\r\n \"protocolo_protesto\": \"PROT-2025-{{randomNumber}}\",\r\n \"protocolo_imovel\": \"IMOV-2025-{{randomNumber}}\",\r\n \"ato_partes\": [\r\n {\r\n \"nome\": \"{{$randomFullName}}\",\r\n \"telefone\": \"{{$randomPhoneNumber}}\",\r\n \"cpf_cnpj\": \"12345678901\"\r\n },\r\n {\r\n \"nome\": \"{{$randomFullName}}\",\r\n \"telefone\": \"{{$randomPhoneNumber}}\",\r\n \"cpf_cnpj\": \"12345678000199\"\r\n }\r\n ],\r\n \"ato_documentos\": [\r\n {\r\n \"url\": \"https://exemplo.com/documentos/ato_2025_0001.pdf\",\r\n \"nome_documento\": \"ATO_2025_0001.pdf\",\r\n \"tipo_documento\": \"ATO_LAVRADO\"\r\n },\r\n {\r\n \"url\": \"https://exemplo.com/documentos/certidao_2025_0001.pdf\",\r\n \"nome_documento\": \"CERTIDAO_2025_0001.pdf\",\r\n \"tipo_documento\": \"CERTIDAO\"\r\n }\r\n ]\r\n\r\n }\r\n\r\n ], \r\n \"ato_partes\": [\r\n {\r\n \"nome\": \"{{$randomFullName}}\",\r\n \"telefone\": \"{{$randomPhoneNumber}}\",\r\n \"cpf_cnpj\": \"12345678901\"\r\n },\r\n {\r\n \"nome\": \"{{$randomFullName}}\",\r\n \"telefone\": \"{{$randomPhoneNumber}}\",\r\n \"cpf_cnpj\": \"12345678000199\"\r\n }\r\n ],\r\n \"ato_documentos\": [\r\n {\r\n \"url\": \"https://exemplo.com/documentos/ato_2025_0001.pdf\",\r\n \"nome_documento\": \"ATO_2025_0001.pdf\",\r\n \"tipo_documento\": \"ATO_LAVRADO\"\r\n },\r\n {\r\n \"url\": \"https://exemplo.com/documentos/certidao_2025_0001.pdf\",\r\n \"nome_documento\": \"CERTIDAO_2025_0001.pdf\",\r\n \"tipo_documento\": \"CERTIDAO\"\r\n }\r\n ] \r\n },\r\n {\r\n \"identificacao_pedido_cgj\": {{randomNumber}},\r\n \"tipo_ato\": {{randomNumber}},\r\n \"codigo_selo\": \"{{$randomColor}}{{$randomAlphaNumeric}}{{$randomAlphaNumeric}}\",\r\n \"codigo_ato\": \"{{$randomColor}}{{$randomAlphaNumeric}}{{randomNumber}}\",\r\n \"nome_civil_ato\": \"{{$randomFullName}}\",\r\n \"nome_serventuario_praticou_ato\": \"{{$randomFullName}}\",\r\n \"data_solicitacao\": \"2025-10-21 15:30:00\",\r\n \"ip_maquina\": \"{{$randomIP}}\",\r\n \"inteiro_teor\": \"Texto do inteiro teor\",\r\n \"valor_entrada\": {{$randomPrice}},\r\n \"emolumento\": {{$randomPrice}},\r\n \"taxa_judiciaria\": {{$randomPrice}},\r\n \"fundos_estaduais\": {{$randomPrice}},\r\n \"protocolo_protesto\": \"PROT-2025-{{randomNumber}}\",\r\n \"protocolo_imovel\": \"IMOV-2025-{{randomNumber}}\",\r\n \"atos_vinculados\": [\r\n {\r\n \"identificacao_pedido_cgj\": {{randomNumber}},\r\n \"tipo_ato\": {{randomNumber}},\r\n \"codigo_selo\": \"{{$randomColor}}{{$randomAlphaNumeric}}{{$randomAlphaNumeric}}\",\r\n \"codigo_ato\": \"{{$randomColor}}{{$randomAlphaNumeric}}{{randomNumber}}\",\r\n \"nome_civil_ato\": \"{{$randomFullName}}\",\r\n \"nome_serventuario_praticou_ato\": \"{{$randomFullName}}\",\r\n \"data_solicitacao\": \"2025-10-21 15:30:00\",\r\n \"ip_maquina\": \"238.206.165.76\",\r\n \"inteiro_teor\": \"Texto do inteiro teor\",\r\n \"valor_entrada\": {{$randomPrice}},\r\n \"emolumento\": {{$randomPrice}},\r\n \"taxa_judiciaria\": {{$randomPrice}},\r\n \"fundos_estaduais\": {{$randomPrice}},\r\n \"protocolo_protesto\": \"PROT-2025-{{randomNumber}}\",\r\n \"protocolo_imovel\": \"IMOV-2025-{{randomNumber}}\",\r\n \"ato_partes\": [\r\n {\r\n \"nome\": \"{{$randomFullName}}\",\r\n \"telefone\": \"{{$randomPhoneNumber}}\",\r\n \"cpf_cnpj\": \"12345678901\"\r\n },\r\n {\r\n \"nome\": \"{{$randomFullName}}\",\r\n \"telefone\": \"{{$randomPhoneNumber}}\",\r\n \"cpf_cnpj\": \"12345678000199\"\r\n }\r\n ],\r\n \"ato_documentos\": [\r\n {\r\n \"url\": \"https://exemplo.com/documentos/ato_2025_0001.pdf\",\r\n \"nome_documento\": \"ATO_2025_0001.pdf\",\r\n \"tipo_documento\": \"ATO_LAVRADO\"\r\n },\r\n {\r\n \"url\": \"https://exemplo.com/documentos/certidao_2025_0001.pdf\",\r\n \"nome_documento\": \"CERTIDAO_2025_0001.pdf\",\r\n \"tipo_documento\": \"CERTIDAO\"\r\n }\r\n ]\r\n\r\n }\r\n\r\n ], \r\n \"ato_partes\": [\r\n {\r\n \"nome\": \"{{$randomFullName}}\",\r\n \"telefone\": \"{{$randomPhoneNumber}}\",\r\n \"cpf_cnpj\": \"12345678901\"\r\n },\r\n {\r\n \"nome\": \"{{$randomFullName}}\",\r\n \"telefone\": \"{{$randomPhoneNumber}}\",\r\n \"cpf_cnpj\": \"12345678000199\"\r\n }\r\n ],\r\n \"ato_documentos\": [\r\n {\r\n \"url\": \"https://exemplo.com/documentos/ato_2025_0001.pdf\",\r\n \"nome_documento\": \"ATO_2025_0001.pdf\",\r\n \"tipo_documento\": \"ATO_LAVRADO\"\r\n },\r\n {\r\n \"url\": \"https://exemplo.com/documentos/certidao_2025_0001.pdf\",\r\n \"nome_documento\": \"CERTIDAO_2025_0001.pdf\",\r\n \"tipo_documento\": \"CERTIDAO\"\r\n }\r\n ] \r\n },\r\n {\r\n \"identificacao_pedido_cgj\": {{randomNumber}},\r\n \"tipo_ato\": {{randomNumber}},\r\n \"codigo_selo\": \"{{$randomColor}}{{$randomAlphaNumeric}}{{$randomAlphaNumeric}}\",\r\n \"codigo_ato\": \"{{$randomColor}}{{$randomAlphaNumeric}}{{randomNumber}}\",\r\n \"nome_civil_ato\": \"{{$randomFullName}}\",\r\n \"nome_serventuario_praticou_ato\": \"{{$randomFullName}}\",\r\n \"data_solicitacao\": \"2025-10-21 15:30:00\",\r\n \"ip_maquina\": \"{{$randomIP}}\",\r\n \"inteiro_teor\": \"Texto do inteiro teor\",\r\n \"valor_entrada\": {{$randomPrice}},\r\n \"emolumento\": {{$randomPrice}},\r\n \"taxa_judiciaria\": {{$randomPrice}},\r\n \"fundos_estaduais\": {{$randomPrice}},\r\n \"protocolo_protesto\": \"PROT-2025-{{randomNumber}}\",\r\n \"protocolo_imovel\": \"IMOV-2025-{{randomNumber}}\",\r\n \"atos_vinculados\": [\r\n {\r\n \"identificacao_pedido_cgj\": {{randomNumber}},\r\n \"tipo_ato\": {{randomNumber}},\r\n \"codigo_selo\": \"{{$randomColor}}{{$randomAlphaNumeric}}{{$randomAlphaNumeric}}\",\r\n \"codigo_ato\": \"{{$randomColor}}{{$randomAlphaNumeric}}{{randomNumber}}\",\r\n \"nome_civil_ato\": \"{{$randomFullName}}\",\r\n \"nome_serventuario_praticou_ato\": \"{{$randomFullName}}\",\r\n \"data_solicitacao\": \"2025-10-21 15:30:00\",\r\n \"ip_maquina\": \"{{$randomIP}}\",\r\n \"inteiro_teor\": \"Texto do inteiro teor\",\r\n \"valor_entrada\": {{$randomPrice}},\r\n \"emolumento\": {{$randomPrice}},\r\n \"taxa_judiciaria\": {{$randomPrice}},\r\n \"fundos_estaduais\": {{$randomPrice}},\r\n \"protocolo_protesto\": \"PROT-2025-{{randomNumber}}\",\r\n \"protocolo_imovel\": \"IMOV-2025-{{randomNumber}}\",\r\n \"ato_partes\": [\r\n {\r\n \"nome\": \"Carlos Pereira\",\r\n \"telefone\": \"{{$randomPhoneNumber}}\",\r\n \"cpf_cnpj\": \"12345678901\"\r\n },\r\n {\r\n \"nome\": \"{{$randomFullName}}\",\r\n \"telefone\": \"{{$randomPhoneNumber}}\",\r\n \"cpf_cnpj\": \"12345678000199\"\r\n }\r\n ],\r\n \"ato_documentos\": [\r\n {\r\n \"url\": \"https://exemplo.com/documentos/ato_2025_0001.pdf\",\r\n \"nome_documento\": \"ATO_2025_0001.pdf\",\r\n \"tipo_documento\": \"ATO_LAVRADO\"\r\n },\r\n {\r\n \"url\": \"https://exemplo.com/documentos/certidao_2025_0001.pdf\",\r\n \"nome_documento\": \"CERTIDAO_2025_0001.pdf\",\r\n \"tipo_documento\": \"CERTIDAO\"\r\n }\r\n ]\r\n\r\n }\r\n\r\n ], \r\n \"ato_partes\": [\r\n {\r\n \"nome\": \"{{$randomFullName}}\",\r\n \"telefone\": \"{{$randomPhoneNumber}}\",\r\n \"cpf_cnpj\": \"12345678901\"\r\n },\r\n {\r\n \"nome\": \"{{$randomFullName}}\",\r\n \"telefone\": \"{{$randomPhoneNumber}}\",\r\n \"cpf_cnpj\": \"12345678000199\"\r\n }\r\n ],\r\n \"ato_documentos\": [\r\n {\r\n \"url\": \"https://exemplo.com/documentos/ato_2025_0001.pdf\",\r\n \"nome_documento\": \"ATO_2025_0001.pdf\",\r\n \"tipo_documento\": \"ATO_LAVRADO\"\r\n },\r\n {\r\n \"url\": \"https://exemplo.com/documentos/certidao_2025_0001.pdf\",\r\n \"nome_documento\": \"CERTIDAO_2025_0001.pdf\",\r\n \"tipo_documento\": \"CERTIDAO\"\r\n }\r\n ] \r\n } \r\n]\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/ato/batch", + "host": [ + "{{url}}" + ], + "path": [ + "ato", + "batch" + ] + } + }, + "response": [] + }, + { + "name": "Atualizar", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BearerToken}}", + "type": "string" + } + ] + }, + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"origem_ato_principal_id\": 1,\r\n \"identificacao_pedido_cgj\": {{randomNumber}},\r\n \"tipo_ato\": {{randomNumber}},\r\n \"codigo_selo\": \"{{$randomAlphaNumeric}}{{$randomAlphaNumeric}}\",\r\n \"codigo_ato\": \"{{$randomAlphaNumeric}}{{randomNumber}}\",\r\n \"nome_civil_ato\": \"{{$randomFullName}}\",\r\n \"nome_serventuario_praticou_ato\": \"{{$randomFullName}}\",\r\n \"data_solicitacao\": \"2025-10-21 15:30:00\",\r\n \"ip_maquina\": \"238.206.165.76\",\r\n \"inteiro_teor\": \"Texto do inteiro teor\",\r\n \"valor_entrada\": {{$randomPrice}},\r\n \"emolumento\": {{$randomPrice}},\r\n \"taxa_judiciaria\": {{$randomPrice}},\r\n \"fundos_estaduais\": {{$randomPrice}},\r\n \"protocolo_protesto\": \"PROT-2025-{{randomNumber}}\",\r\n \"protocolo_imovel\": \"IMOV-2025-{{randomNumber}}\"\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/ato/3", + "host": [ + "{{url}}" + ], + "path": [ + "ato", + "3" + ] + } + }, + "response": [] + }, + { + "name": "Localizar ID", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BearerToken}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/ato/3", + "host": [ + "{{url}}" + ], + "path": [ + "ato", + "3" + ] + } + }, + "response": [] + }, + { + "name": "Deletar", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{BearerToken}}", + "type": "string" + } + ] + }, + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/ato/5", + "host": [ + "{{url}}" + ], + "path": [ + "ato", + "5" + ] + } + }, + "response": [] + } + ] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "packages": {}, + "requests": {}, + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "packages": {}, + "requests": {}, + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "url", + "value": "" + }, + { + "key": "BearerToken", + "value": "" + } + ] +} \ No newline at end of file diff --git a/packages/v1/administrativo/repositories/ato_principal/ato_principal_save_multiple_repository.py b/packages/v1/administrativo/repositories/ato_principal/ato_principal_save_multiple_repository.py index f8a9113..19b3a8e 100644 --- a/packages/v1/administrativo/repositories/ato_principal/ato_principal_save_multiple_repository.py +++ b/packages/v1/administrativo/repositories/ato_principal/ato_principal_save_multiple_repository.py @@ -1,8 +1,11 @@ -from typing import List, Optional +import hashlib +import logging +from typing import List, Optional, Dict, Any from fastapi import HTTPException, status -import traceback -from sqlalchemy import func -from sqlalchemy.orm import Session # Importação para tipagem da session +from sqlalchemy import text +from sqlalchemy.orm import Session +from sqlalchemy.exc import IntegrityError, OperationalError, SQLAlchemyError + from database.mysql import SessionLocal, get_database_settings from packages.v1.administrativo.models.ato_principal_model import AtoPrincipal from packages.v1.administrativo.models.ato_parte_model import AtoParte @@ -11,6 +14,12 @@ from packages.v1.administrativo.schemas.ato_principal_schema import ( AtoPrincipalSaveSchema, ) +# Configuração de logging +logging.basicConfig( + level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" +) +logger = logging.getLogger(__name__) + # Configuração da Chave AES DB_SETTINGS = get_database_settings() AES_KEY = getattr(DB_SETTINGS, "aeskey", None) @@ -18,11 +27,168 @@ AES_KEY = getattr(DB_SETTINGS, "aeskey", None) class SaveMultipleRepository: """ - Repositório para salvar múltiplos atos principais com suas partes e documentos, - usando criptografia nativa do MySQL via AES_ENCRYPT. - Implementa lógica recursiva para atos vinculados. + Repositório otimizado para salvar múltiplos atos principais com suas partes + e documentos, usando criptografia nativa do MySQL via AES_ENCRYPT. + + Melhorias implementadas: + - Criptografia correta via execução SQL + - Hash SHA256 para busca rápida de duplicidades + - Gerenciamento adequado de sessões (uma por transação) + - Logging profissional estruturado + - Tratamento de exceções específicas + - Validação robusta da chave AES """ + def __init__(self): + """Inicializa o repositório e valida a configuração da chave AES""" + if not AES_KEY: + raise ValueError( + "A chave AES (aeskey) não está configurada. " + "Verifique as configurações do banco de dados." + ) + logger.info("SaveMultipleRepository inicializado com sucesso") + + @staticmethod + def _generate_hash(value: str) -> str: + """ + Gera hash SHA256 para busca rápida e verificação de duplicidade. + + Args: + value: Valor a ser hasheado + + Returns: + Hash SHA256 em formato hexadecimal + """ + if not value: + return None + return hashlib.sha256(value.encode("utf-8")).hexdigest() + + def _encrypt_field(self, db: Session, value: str) -> Optional[bytes]: + """ + Criptografa um campo usando AES_ENCRYPT do MySQL. + + Args: + db: Sessão do banco de dados + value: Valor a ser criptografado + + Returns: + Valor criptografado em bytes ou None se valor vazio + """ + if not value or (isinstance(value, str) and not value.strip()): + return None + + try: + result = db.execute( + text("SELECT AES_ENCRYPT(:val, :key) as encrypted"), + {"val": value.strip(), "key": AES_KEY}, + ).scalar() + return result + except Exception as e: + logger.error(f"Erro ao criptografar campo: {str(e)}") + raise + + def _check_duplicate_codigo_selo(self, db: Session, codigo_selo: str) -> bool: + """ + Verifica se o código do selo já existe usando hash para busca rápida. + + Args: + db: Sessão do banco de dados + codigo_selo: Código do selo a verificar + + Returns: + True se já existe, False caso contrário + """ + codigo_hash = self._generate_hash(codigo_selo) + + existing = ( + db.query(AtoPrincipal) + .filter(AtoPrincipal.codigo_selo_hash == codigo_hash) + .first() + ) + + return existing is not None + + def _prepare_encrypted_data( + self, db: Session, data: Dict[str, Any], fields_to_encrypt: List[str] + ) -> Dict[str, Any]: + """ + Prepara os dados criptografando os campos especificados. + + Args: + db: Sessão do banco de dados + data: Dicionário com os dados + fields_to_encrypt: Lista de campos a criptografar + + Returns: + Dicionário com campos criptografados + """ + processed_data = data.copy() + + for field in fields_to_encrypt: + value = data.get(field) + if value is not None and str(value).strip(): + processed_data[field] = self._encrypt_field(db, str(value)) + else: + processed_data[field] = None + + return processed_data + + def _save_ato_partes( + self, db: Session, partes: List, ato_principal_id: int + ) -> None: + """ + Salva as partes de um ato principal. + + Args: + db: Sessão do banco de dados + partes: Lista de schemas de partes + ato_principal_id: ID do ato principal + """ + campos_criptografar = ["nome", "telefone", "cpf_cnpj"] + + for parte in partes: + parte_data = parte.model_dump(exclude_unset=True) + + # Criptografa campos sensíveis + parte_data = self._prepare_encrypted_data( + db, parte_data, campos_criptografar + ) + + # Adiciona relacionamento + parte_data["ato_principal_id"] = ato_principal_id + + new_parte = AtoParte(**parte_data) + db.add(new_parte) + + logger.debug(f"Salvas {len(partes)} partes para ato {ato_principal_id}") + + def _save_ato_documentos( + self, db: Session, documentos: List, ato_principal_id: int + ) -> None: + """ + Salva os documentos de um ato principal. + + Args: + db: Sessão do banco de dados + documentos: Lista de schemas de documentos + ato_principal_id: ID do ato principal + """ + campos_criptografar = ["url", "nome_documento", "tipo_documento"] + + for doc in documentos: + doc_data = doc.model_dump(exclude_unset=True) + + # Criptografa campos sensíveis + doc_data = self._prepare_encrypted_data(db, doc_data, campos_criptografar) + + # Adiciona relacionamento + doc_data["ato_principal_id"] = ato_principal_id + + new_documento = AtoDocumento(**doc_data) + db.add(new_documento) + + logger.debug(f"Salvos {len(documentos)} documentos para ato {ato_principal_id}") + def _save_single_recursive_transaction( self, db: Session, @@ -30,95 +196,76 @@ class SaveMultipleRepository: parent_ato_principal_id: Optional[int] = None, ) -> AtoPrincipal: """ - Salva um único Ato Principal, seus filhos (partes/documentos) e - chama recursivamente o salvamento dos atos vinculados. + Salva recursivamente um ato principal com todas suas dependências. + + Args: + db: Sessão do banco de dados + ato_schema: Schema do ato a salvar + parent_ato_principal_id: ID do ato pai (para atos vinculados) + + Returns: + Instância do AtoPrincipal salvo + + Raises: + HTTPException: Se código do selo já existe """ codigo_selo = ato_schema.codigo_selo - # 1. Pré-processamento e Criptografia - ato_data = ato_schema.model_dump( - exclude_unset=True, - exclude={"ato_partes", "ato_documentos", "atos_vinculados"}, - ) - - # Define o ID de origem se for um ato vinculado - if parent_ato_principal_id is not None: - ato_data["origem_ato_principal_id"] = parent_ato_principal_id - elif ato_data.get("origem_ato_principal_id") is None: - ato_data["origem_ato_principal_id"] = None - - # Verifica duplicidade usando descriptografia - existing_ato = ( - db.query(AtoPrincipal) - .filter(func.aes_decrypt(AtoPrincipal.codigo_selo, AES_KEY) == codigo_selo) - .first() - ) - - if existing_ato: + # 1. Verificação de duplicidade usando hash + if self._check_duplicate_codigo_selo(db, codigo_selo): + logger.warning(f"Tentativa de cadastro duplicado: {codigo_selo}") raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail=f"O Código do Selo '{codigo_selo}' já está cadastrado.", ) + # 2. Preparação dos dados do ato principal + ato_data = ato_schema.model_dump( + exclude_unset=True, + exclude={"ato_partes", "ato_documentos", "atos_vinculados"}, + ) + + # Define relacionamento com ato pai + if parent_ato_principal_id is not None: + ato_data["origem_ato_principal_id"] = parent_ato_principal_id + elif "origem_ato_principal_id" not in ato_data: + ato_data["origem_ato_principal_id"] = None + + # 3. Criptografia dos campos sensíveis campos_criptografar = [ "nome_civil_ato", "nome_serventuario_praticou_ato", ] - # Criptografa os campos de texto necessários - for campo in campos_criptografar: - valor = ato_data.get(campo) - if isinstance(valor, str) and valor.strip(): - ato_data[campo] = func.aes_encrypt(valor, AES_KEY) - elif campo not in ato_data or valor is None: - ato_data[campo] = None + ato_data = self._prepare_encrypted_data(db, ato_data, campos_criptografar) - # 2. Criação e Persistência do Ato Principal + # Adiciona hash do código do selo para busca rápida + ato_data["codigo_selo_hash"] = self._generate_hash(codigo_selo) + + # 4. Criação e persistência do ato principal new_ato = AtoPrincipal(**ato_data) db.add(new_ato) - db.flush() + db.flush() # Obtém o ID sem fazer commit + new_ato_id = new_ato.ato_principal_id + logger.info(f"Ato principal criado: ID={new_ato_id}, Selo={codigo_selo}") - # 3. Salva os Filhos Diretos: Ato Partes - for parte in ato_schema.ato_partes: - parte_data = parte.model_dump(exclude_unset=True) + # 5. Salva partes do ato + if ato_schema.ato_partes: + self._save_ato_partes(db, ato_schema.ato_partes, new_ato_id) - parte_campos_criptografar = ["nome", "telefone", "cpf_cnpj"] + # 6. Salva documentos do ato + if ato_schema.ato_documentos: + self._save_ato_documentos(db, ato_schema.ato_documentos, new_ato_id) - for campo in parte_campos_criptografar: - valor = parte_data.get(campo) - # A validação/conversão para string já foi feita pelo Pydantic, - # mas mantemos a checagem de tipo e strip para segurança antes da criptografia - if isinstance(valor, str) and valor.strip(): - parte_data[campo] = func.aes_encrypt(valor, AES_KEY) - else: - parte_data[campo] = None - - new_parte = AtoParte(**parte_data, ato_principal_id=new_ato_id) - db.add(new_parte) - - # 4. Salva os Filhos Diretos: Ato Documentos - for doc in ato_schema.ato_documentos: - doc_data = doc.model_dump(exclude_unset=True) - - doc_campos_criptografar = ["url", "nome_documento", "tipo_documento"] - - for campo in doc_campos_criptografar: - valor = doc_data.get(campo) - if isinstance(valor, str) and valor.strip(): - doc_data[campo] = func.aes_encrypt(valor, AES_KEY) - else: - doc_data[campo] = None - - new_documento = AtoDocumento(**doc_data, ato_principal_id=new_ato_id) - db.add(new_documento) - - # 5. Lógica Recursiva para Atos Vinculados (Estrutura de loop idêntica) + # 7. Salvamento recursivo de atos vinculados if ato_schema.atos_vinculados: + logger.info( + f"Processando {len(ato_schema.atos_vinculados)} atos vinculados " + f"para selo {codigo_selo}" + ) - # A iteração é semelhante, mas o que é executado é a chamada recursiva for linked_ato_schema in ato_schema.atos_vinculados: - # O ato vinculado é persistido chamando a rotina de salvamento completa self._save_single_recursive_transaction( db, linked_ato_schema, @@ -127,70 +274,138 @@ class SaveMultipleRepository: return new_ato - # Método principal (chamado pela Action) - def execute(self, atos_principais: List[AtoPrincipalSaveSchema]): + def _process_single_ato(self, ato_schema: AtoPrincipalSaveSchema) -> Dict[str, Any]: + """ + Processa um único ato em uma transação isolada. + + Args: + ato_schema: Schema do ato a processar + + Returns: + Dicionário com resultado da operação + """ db = SessionLocal() - results = [] + codigo_selo = getattr(ato_schema, "codigo_selo", "CÓDIGO_INDISPONÍVEL") - # 1. Checa a chave AES - if not AES_KEY: + try: + logger.info(f"Iniciando processamento do selo: {codigo_selo}") + + # Salva o ato com toda sua hierarquia + saved_ato = self._save_single_recursive_transaction( + db, ato_schema, parent_ato_principal_id=None + ) + + # Commit da transação completa + db.commit() + + logger.info( + f"Ato salvo com sucesso: ID={saved_ato.ato_principal_id}, " + f"Selo={codigo_selo}" + ) + + return { + "success": True, + "message": "Ato Principal e vinculados salvos com sucesso", + "data": { + "ato_principal_id": saved_ato.ato_principal_id, + "codigo_selo": codigo_selo, + "tipo_ato": saved_ato.tipo_ato, + }, + } + + except HTTPException as he: + db.rollback() + logger.warning(f"Erro HTTP ao processar selo {codigo_selo}: {he.detail}") + return { + "success": False, + "error": he.detail, + "data": {"codigo_selo": codigo_selo}, + } + + except IntegrityError as ie: + db.rollback() + logger.error( + f"Erro de integridade ao processar selo {codigo_selo}: {str(ie)}", + exc_info=True, + ) + return { + "success": False, + "error": "Erro de integridade: violação de constraint no banco de dados", + "data": {"codigo_selo": codigo_selo}, + } + + except OperationalError as oe: + db.rollback() + logger.error( + f"Erro operacional ao processar selo {codigo_selo}: {str(oe)}", + exc_info=True, + ) + return { + "success": False, + "error": "Erro de conexão ou operação no banco de dados", + "data": {"codigo_selo": codigo_selo}, + } + + except SQLAlchemyError as se: + db.rollback() + logger.error( + f"Erro SQLAlchemy ao processar selo {codigo_selo}: {str(se)}", + exc_info=True, + ) + return { + "success": False, + "error": "Erro ao interagir com o banco de dados", + "data": {"codigo_selo": codigo_selo}, + } + + except Exception as e: + db.rollback() + logger.error( + f"Erro inesperado ao processar selo {codigo_selo}: {str(e)}", + exc_info=True, + ) + return { + "success": False, + "error": f"Erro inesperado: {str(e)}", + "data": {"codigo_selo": codigo_selo}, + } + + finally: db.close() - raise Exception("A chave AES (aeskey) não está configurada.") - # 2. Loop principal: Cada iteração é uma transação completa (incluindo recursão) - for ato_schema in atos_principais: - codigo_selo_log = getattr(ato_schema, "codigo_selo", "SELO_INDISPONÍVEL") + def execute( + self, atos_principais: List[AtoPrincipalSaveSchema] + ) -> List[Dict[str, Any]]: + """ + Método principal para salvar múltiplos atos principais. + Cada ato é processado em uma transação independente. - try: - # A rotina completa de salvamento (incluindo filhos e recursão) é encapsulada - saved_ato = self._save_single_recursive_transaction( - db, - ato_schema, - parent_ato_principal_id=None, # Ato de nível superior - ) + Args: + atos_principais: Lista de schemas de atos a salvar - # ---------- COMMIT final para a transação completa (Ato Principal + Filhos + Atos Vinculados) ---------- - db.commit() + Returns: + Lista de dicionários com resultado de cada operação + """ + logger.info(f"Iniciando processamento de {len(atos_principais)} atos") - # Retorno de sucesso - ato_result = { - "success": True, - "message": "Ato Principal e vinculados salvos com sucesso", - "data": { - "ato_principal_id": saved_ato.ato_principal_id, - "codigo_selo": codigo_selo_log, - "tipo_ato": saved_ato.tipo_ato, - }, - } - results.append(ato_result) + results = [] + successful_count = 0 + failed_count = 0 - # Tratamento de erro específico para duplicidade ou HTTP - except HTTPException as he: - db.rollback() - results.append( - { - "success": False, - "error": he.detail, - "data": {"codigo_selo": codigo_selo_log}, - } - ) + for idx, ato_schema in enumerate(atos_principais, 1): + logger.info(f"Processando ato {idx}/{len(atos_principais)}") - # Tratamento de erro genérico - except Exception as e: - db.rollback() + result = self._process_single_ato(ato_schema) + results.append(result) - # Log completo do erro - print(f"ERRO DE PERSISTÊNCIA NO SELO: {codigo_selo_log}") - traceback.print_exc() - print("--------------") + if result["success"]: + successful_count += 1 + else: + failed_count += 1 - results.append( - { - "success": False, - "error": "Erro ao salvar o registro. Verifique o formato dos dados ou os logs do servidor.", - "data": {"codigo_selo": codigo_selo_log}, - } - ) + logger.info( + f"Processamento concluído: {successful_count} sucessos, " + f"{failed_count} falhas" + ) - db.close() return results diff --git a/requirements.txt b/requirements.txt index 5567c00..e2d69f2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,36 +1,60 @@ annotated-types==0.7.0 -anyio==4.10.0 -bcrypt==3.1.7 -cffi==2.0.0 +anyio==4.9.0 +asyncpg==0.30.0 +attrs==25.3.0 +bcrypt==3.2.0 +certifi==2025.4.26 +cffi==1.17.1 click==8.2.1 colorama==0.4.6 -cryptography==46.0.3 +cryptography==45.0.2 +distlib==0.3.9 dnspython==2.7.0 ecdsa==0.19.1 email_validator==2.2.0 -fastapi==0.116.1 -firebird-base==2.0.2 -firebird-driver==2.0.2 -greenlet==3.2.4 +fastapi==0.115.12 +filelock==3.18.0 +future==1.0.0 +greenlet==3.2.2 h11==0.16.0 idna==3.10 +mysql-connector-python==9.3.0 +outcome==1.3.0.post0 packaging==25.0 passlib==1.7.4 -protobuf==5.29.5 -pyasn1==0.6.1 +pbr==6.1.1 +platformdirs==4.3.8 +protobuf==5.29.4 +psycopg2==2.9.11 +pyasn1==0.4.8 pycparser==2.22 -pydantic==2.11.7 +pydantic==2.11.4 +pydantic-settings==2.9.1 pydantic_core==2.33.2 -PyMySQL==1.1.2 +PyMySQL==1.1.1 +PySocks==1.7.1 python-dateutil==2.9.0.post0 -python-jose==3.5.0 +python-dotenv==1.1.0 +python-jose==3.4.0 +python-multipart==0.0.20 pytz==2025.2 rsa==4.9.1 +setuptools==80.8.0 six==1.17.0 sniffio==1.3.1 -SQLAlchemy==2.0.42 -sqlalchemy-firebird==2.1 -starlette==0.47.2 -typing-inspection==0.4.1 -typing_extensions==4.14.1 -uvicorn==0.35.0 +sortedcontainers==2.4.0 +SQLAlchemy==2.0.41 +starlette==0.46.2 +stevedore==5.4.1 +trio==0.30.0 +trio-websocket==0.12.2 +typing-inspection==0.4.0 +typing_extensions==4.13.2 +urllib3==2.4.0 +uvicorn==0.34.2 +virtualenv==20.31.2 +virtualenv-clone==0.5.7 +virtualenvwrapper==6.1.1 +virtualenvwrapper-win==1.2.7 +websocket-client==1.8.0 +wsproto==1.2.0