Skip to content

Commit f33236b

Browse files
Merge pull request #5 from PythonFloripa/dev
Dev
2 parents c3e9f7d + e8a3c0c commit f33236b

File tree

4 files changed

+170
-1
lines changed

4 files changed

+170
-1
lines changed

README.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,91 @@ Cria um novo certificado para um determinado produto.
4646
}
4747
```
4848

49+
### Criar Certificados em Lote
50+
51+
Cria múltiplos certificados a partir de uma lista de dados recebida diretamente.
52+
53+
- **Endpoint:** `POST /v1/certificate/create-batch`
54+
- **Entrada (body):**
55+
```json
56+
{
57+
"certificates": [
58+
{
59+
"order_id": 1234,
60+
"first_name": "João",
61+
"last_name": "Silva",
62+
"email": "[email protected]",
63+
"phone": "(48) 99999-9999",
64+
"cpf": "123.456.789-00",
65+
"city": "Florianópolis",
66+
"product_id": 5678,
67+
"product_name": "Workshop de Python Avançado",
68+
"certificate_details": "In recognition of their participation in the Workshop de Python Avançado, held on January 15, 2025, at IFSC – Câmpus Florianópolis, Brazil, with a total duration of 8 hours.",
69+
"certificate_logo": "https://example.com/logo.png",
70+
"certificate_background": "https://example.com/background.png",
71+
"order_date": "2025-01-10 14:30:00",
72+
"checkin_latitude": "-27.5667",
73+
"checkin_longitude": "-48.5156",
74+
"time_checkin": "2025-01-15 09:00:00"
75+
},
76+
{
77+
"order_id": 1235,
78+
"first_name": "Maria",
79+
"last_name": "Santos",
80+
"email": "[email protected]",
81+
"phone": "(48) 88888-8888",
82+
"cpf": "987.654.321-00",
83+
"city": "São José",
84+
"product_id": 5678,
85+
"product_name": "Workshop de Python Avançado",
86+
"certificate_details": "In recognition of their participation in the Workshop de Python Avançado, held on January 15, 2025, at IFSC – Câmpus Florianópolis, Brazil, with a total duration of 8 hours.",
87+
"certificate_logo": "https://example.com/logo.png",
88+
"certificate_background": "https://example.com/background.png",
89+
"order_date": "2025-01-10 14:35:00",
90+
"checkin_latitude": "-27.5667",
91+
"checkin_longitude": "-48.5156",
92+
"time_checkin": "2025-01-15 09:05:00"
93+
}
94+
]
95+
}
96+
```
97+
- **Campos obrigatórios:**
98+
- `order_id`: ID único do pedido (integer)
99+
- `first_name`: Primeiro nome do participante (string)
100+
- `last_name`: Sobrenome do participante (string)
101+
- `email`: Email do participante (string)
102+
- `phone`: Telefone do participante (string)
103+
- `cpf`: CPF do participante (string, pode ser vazio)
104+
- `city`: Cidade do participante (string)
105+
- `product_id`: ID do produto (integer)
106+
- `product_name`: Nome do produto (string)
107+
- `certificate_details`: Detalhes do certificado (string)
108+
- `certificate_logo`: URL do logo do certificado (string)
109+
- `certificate_background`: URL do background do certificado (string)
110+
- `order_date`: Data do pedido no formato "YYYY-MM-DD HH:MM:SS" (string)
111+
- **Campos opcionais:**
112+
- `checkin_latitude`: Latitude do check-in (string, opcional)
113+
- `checkin_longitude`: Longitude do check-in (string, opcional)
114+
- `time_checkin`: Data e hora do check-in no formato "YYYY-MM-DD HH:MM:SS" (string, opcional)
115+
- **Nota:** Certificados sem `time_checkin` serão marcados como inválidos e não serão processados.
116+
- **Saída (sucesso):**
117+
```json
118+
{
119+
"certificate_quantity": 2,
120+
"existing_orders": [],
121+
"new_orders": [1234, 1235],
122+
"processing_date": "2025-01-20 10:30:45.123456"
123+
}
124+
```
125+
- **Saída (erro):**
126+
```json
127+
{
128+
"status": 500,
129+
"message": "Internal Server Error",
130+
"details": "string"
131+
}
132+
```
133+
49134
### Consultar Certificado
50135

51136
Consulta certificados com base em diferentes critérios.

src/main/handler/certificate.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import logging
22
from typing import List
33
from src.main.presentation.http_types.create_certificate import CreateCertificateRequest
4+
from src.main.presentation.http_types.create_certificates import CreateCertificatesRequest
45
from src.main.presentation.http_types.fetch_certificate import FetchCertificateRequest, FetchCertificateResponse
56
from src.main.presentation.http_types.download_certificate import DownloadCertificateRequest, DownloadCertificateResponse
67
from src.application.dto.fetch_certificate_dto import FetchCertificateRequestDto
@@ -106,3 +107,38 @@ def download_certificate_handler(request: DownloadCertificateRequest) -> Downloa
106107
)
107108

108109
return response
110+
111+
112+
def create_certificates_handler(request: CreateCertificatesRequest) -> BuildOrderResponse:
113+
"""
114+
Handler para processar uma lista de certificados recebida diretamente.
115+
Reaproveita a lógica do CreateCertificate sem buscar da API externa.
116+
"""
117+
logger.info(f"Iniciando processamento de {len(request.certificates)} certificados recebidos")
118+
119+
create_certificate: CreateCertificate = container.get('create_certificate')
120+
send_for_build_certificate: SendForBuildCertificate = container.get('send_for_build_certificate')
121+
122+
# Converte os certificados recebidos para TechOrdersResponse
123+
tech_orders: List[TechOrdersResponse] = [
124+
TechOrdersResponse.model_validate(cert.model_dump())
125+
for cert in request.certificates
126+
]
127+
128+
logger.info(f"Convertidos {len(tech_orders)} certificados para TechOrdersResponse")
129+
130+
# Processa os certificados usando a mesma lógica do CreateCertificate
131+
processed_orders: ProcessedOrdersResponse = create_certificate.execute(tech_orders)
132+
133+
# Envia as ordens válidas para construção de certificados
134+
if len(processed_orders.valid_orders) > 0:
135+
logger.info(f"Enviando {len(processed_orders.valid_orders)} novas ordens para construção de certificados")
136+
send_for_build_certificate.execute(processed_orders.valid_orders)
137+
else:
138+
logger.info("Nenhuma ordem nova para enviar para construção de certificados")
139+
140+
return BuildOrderResponse(
141+
certificate_quantity=len(tech_orders),
142+
existing_orders=[order.order_id for order in processed_orders.invalid_orders],
143+
new_orders=[order.order_id for order in processed_orders.valid_orders]
144+
)

src/main/presentation/controller/certificate.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@
99
from src.infrastructure.config.config import config
1010

1111
from src.main.presentation.http_types.create_certificate import CreateCertificateRequest
12+
from src.main.presentation.http_types.create_certificates import CreateCertificatesRequest
1213
from src.main.presentation.http_types.fetch_certificate import FetchCertificateRequest, FetchCertificateResponse
1314
from src.main.presentation.http_types.download_certificate import DownloadCertificateRequest, DownloadCertificateResponse
14-
from src.main.handler.certificate import create_certificate_handler, fetch_certificate_handler, download_certificate_handler
15+
from src.main.handler.certificate import create_certificate_handler, create_certificates_handler, fetch_certificate_handler, download_certificate_handler
1516
from src.main.presentation.template_loader import template_loader
1617
from src.domain.response.build_order import BuildOrderResponse
1718
from src.domain.response.failed import FailedResponse
@@ -35,6 +36,25 @@ def create_certificate() -> BuildOrderResponse:
3536
status=500
3637
)
3738

39+
40+
@app.post(f"{config.PREFIX_API_VERSION}/certificate/create-batch")
41+
def create_certificates() -> BuildOrderResponse:
42+
"""
43+
Endpoint para receber uma lista de certificados e processá-los.
44+
Recebe uma lista de objetos de certificado e processa cada um deles.
45+
"""
46+
try:
47+
request: CreateCertificatesRequest = parse(app.current_event.body, CreateCertificatesRequest)
48+
response: BuildOrderResponse = create_certificates_handler(request)
49+
return response
50+
except Exception as e:
51+
logger.error(f"Erro ao processar a requisição de certificados em lote: {e}")
52+
return FailedResponse(
53+
details=str(e),
54+
message="Internal Server Error",
55+
status=500
56+
)
57+
3858

3959
@app.get(f"{config.PREFIX_API_VERSION}/certificate/fetch")
4060
def fetch_certificate(
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from pydantic import BaseModel
2+
from typing import List, Optional
3+
4+
5+
class CertificateItemRequest(BaseModel):
6+
"""Modelo para um item individual de certificado na lista"""
7+
order_id: int
8+
first_name: str
9+
last_name: str
10+
email: str
11+
phone: str
12+
cpf: str
13+
city: str
14+
product_id: int
15+
product_name: str
16+
certificate_details: str
17+
certificate_logo: str
18+
certificate_background: str
19+
order_date: str
20+
checkin_latitude: Optional[str] = None
21+
checkin_longitude: Optional[str] = None
22+
time_checkin: Optional[str] = None
23+
24+
25+
class CreateCertificatesRequest(BaseModel):
26+
"""Request para criação de múltiplos certificados"""
27+
certificates: List[CertificateItemRequest]
28+

0 commit comments

Comments
 (0)