diff --git a/.cursor/rules/architecture.mdc b/.cursor/rules/architecture.mdc new file mode 100644 index 0000000..d1cbb53 --- /dev/null +++ b/.cursor/rules/architecture.mdc @@ -0,0 +1,333 @@ +--- +description: +globs: +alwaysApply: true +--- +# Mercado Pago Python SDK - Cursor Rules + +## Visão Geral do Projeto +Este é o SDK oficial do Mercado Pago para Python, uma biblioteca de processamento de pagamentos que segue as melhores práticas Python (PEP 8, PEP 257) e convenções da comunidade. O SDK é distribuído como um pacote Python e segue uma arquitetura modular com clara separação de responsabilidades. + +## Estrutura e Organização do Projeto + +### Estrutura de Diretórios Principal +``` +mercadopago/ # Pacote principal +├── __init__.py # Inicialização do pacote +├── sdk.py # Classe principal do SDK +├── core/ # Funcionalidades principais +│ ├── __init__.py +│ ├── base_client.py # Cliente base abstrato +│ └── base_resource.py # Recurso base abstrato +├── resources/ # Recursos da API +│ ├── __init__.py +│ ├── payment.py +│ └── order.py +├── http/ # Manipulação HTTP +│ ├── __init__.py +│ ├── http_client.py +│ └── response.py +├── config/ # Configurações +│ ├── __init__.py +│ └── config.py +└── examples/ # Exemplos de uso +tests/ # Testes automatizados +docs/ # Documentação +``` + +## Convenções de Nomenclatura + +### Classes e Módulos +- **Clientes**: `{Resource}Client` (ex: `PaymentClient`, `OrderClient`) +- **Recursos**: `{Resource}` (ex: `Payment`, `Order`) +- **Configuração**: `Config`, `Settings` +- **Exceções**: `{Type}Error` (ex: `ValidationError`, `APIError`) + +### Métodos e Variáveis +- Usar **snake_case** para nomes de métodos e variáveis +- Métodos privados começam com underscore +- Constantes em **SCREAMING_SNAKE_CASE** +- Variáveis de instância sem prefixo especial + +### Arquivos e Diretórios +- Arquivos em **snake_case.py** +- Um módulo por arquivo +- Nomes de arquivo devem corresponder ao módulo principal +- Testes em `test_*.py` + +## Padrões de Código + +### Estilo Python +- Seguir PEP 8 (Guia de Estilo) +- Seguir PEP 257 (Docstrings) +- Usar Black para formatação +- Usar isort para imports +- Usar pylint/flake8 para linting +- Linhas com máximo de 88 caracteres (Black default) + +### Padrões de Cliente +```python +from typing import Dict, Optional + +class PaymentClient(BaseClient): + """Cliente para operações de pagamento.""" + + def create(self, payment_data: Dict, options: Optional[Dict] = None) -> Payment: + """Cria um novo pagamento. + + Args: + payment_data: Dados do pagamento + options: Opções adicionais + + Returns: + Payment: O pagamento criado + + Raises: + ValidationError: Se os dados forem inválidos + APIError: Se houver erro na API + """ + return self.post('/v1/payments', data=payment_data, options=options) +``` + +### Padrões de Recurso +```python +from dataclasses import dataclass +from typing import Optional + +@dataclass +class Payment: + """Representa um pagamento.""" + + id: int + status: str + description: Optional[str] = None + + @property + def is_approved(self) -> bool: + """Verifica se o pagamento foi aprovado.""" + return self.status == 'approved' +``` + +## Práticas de Desenvolvimento + +### Geral +- Usar type hints (PEP 484) +- Preferir dataclasses para modelos +- Usar async/await para operações I/O +- Seguir princípios SOLID +- Documentar com docstrings + +### Tratamento de Erros +```python +class APIError(Exception): + """Erro retornado pela API.""" + + def __init__(self, message: str, status_code: int, details: Dict): + super().__init__(message) + self.status_code = status_code + self.details = details +``` + +### Logging +```python +import logging +from typing import Any + +logger = logging.getLogger(__name__) + +def process_payment(payment_data: Dict[str, Any]) -> None: + """Processa um pagamento com logging apropriado.""" + try: + logger.info("Iniciando processamento de pagamento", extra={"payment_id": payment_data.get("id")}) + # Processamento + logger.info("Pagamento processado com sucesso") + except Exception as e: + logger.error("Erro no processamento do pagamento", exc_info=True) + raise +``` + +## Testes + +### Estrutura de Testes +- Usar pytest como framework +- Organizar testes espelhando a estrutura do código +- Usar fixtures para setup comum +- Implementar testes unitários e de integração + +### Padrões de Teste +```python +import pytest +from unittest.mock import Mock + +def test_payment_creation(): + """Testa a criação de um pagamento.""" + client = PaymentClient(Mock()) + payment_data = {"amount": 100} + + result = client.create(payment_data) + + assert result.id is not None + assert result.status == "pending" + +@pytest.mark.asyncio +async def test_async_payment_creation(): + """Testa a criação assíncrona de um pagamento.""" + client = AsyncPaymentClient(Mock()) + payment_data = {"amount": 100} + + result = await client.create(payment_data) + + assert result.id is not None +``` + +## Documentação + +### Docstrings +- Usar formato Google para docstrings +- Documentar todos os módulos, classes e métodos públicos +- Incluir exemplos de uso +- Documentar tipos com type hints + +```python +def create_payment(amount: float, currency: str = "BRL") -> Payment: + """Cria um novo pagamento. + + Args: + amount: O valor do pagamento + currency: A moeda do pagamento (default: BRL) + + Returns: + Payment: O pagamento criado + + Raises: + ValidationError: Se o valor for negativo + + Example: + >>> payment = create_payment(100.0) + >>> print(payment.status) + 'pending' + """ +``` + +## Gerenciamento de Dependências + +### pyproject.toml +```toml +[tool.poetry] +name = "mercadopago" +version = "2.0.0" +description = "Mercado Pago Python SDK" + +[tool.poetry.dependencies] +python = "^3.7" +requests = "^2.25.0" +pydantic = "^1.8.0" + +[tool.poetry.dev-dependencies] +pytest = "^6.2.0" +black = "^21.5b2" +pylint = "^2.8.0" +``` + +### Compatibilidade +- Suportar Python 3.7+ +- Especificar versões de dependências +- Usar Poetry para gerenciamento +- Testar com diferentes versões Python + +## Segurança + +### Práticas +- Validar todas as entradas +- Sanitizar dados sensíveis +- Usar HTTPS +- Implementar rate limiting +- Seguir OWASP guidelines + +### Dados Sensíveis +```python +import os +from typing import Optional + +class Credentials: + """Gerencia credenciais de forma segura.""" + + def __init__(self): + self._access_token: Optional[str] = None + + @property + def access_token(self) -> str: + """Obtém o token de acesso de forma segura.""" + if not self._access_token: + self._access_token = os.environ.get("MP_ACCESS_TOKEN") + return self._access_token +``` + +## Performance + +### Otimizações +- Usar connection pooling +- Implementar caching +- Otimizar imports +- Usar async/await para I/O + +### Concorrência +```python +import asyncio +from typing import List + +async def process_payments(payments: List[Dict]) -> List[Payment]: + """Processa múltiplos pagamentos concorrentemente.""" + tasks = [process_payment(p) for p in payments] + return await asyncio.gather(*tasks) +``` + +## Controle de Versão + +### Git +- Commits atômicos +- Mensagens descritivas +- Feature branches +- Pull requests + +### Releases +- Semantic Versioning +- CHANGELOG.md +- Release tags +- Documentação de breaking changes + +## Qualidade de Código + +### Ferramentas +- Black para formatação +- Pylint para linting +- Mypy para type checking +- Coverage.py para cobertura + +### CI/CD +- Testes automatizados +- Verificação de tipos +- Análise de código +- Deploy automático + +## Internacionalização + +### i18n +- Usar gettext +- Strings externalizadas +- Suporte a múltiplos idiomas +- Formatação local-aware + +## Manutenção + +### Práticas +- Refatoração contínua +- Remoção de código morto +- Atualização de dependências +- Documentação atualizada + +### Monitoramento +- Logging estruturado +- Métricas de performance +- Rastreamento de erros +- Health checks \ No newline at end of file diff --git a/.cursor/rules/role_playing.mdc b/.cursor/rules/role_playing.mdc new file mode 100644 index 0000000..9deefa2 --- /dev/null +++ b/.cursor/rules/role_playing.mdc @@ -0,0 +1,86 @@ +--- +description: +globs: +alwaysApply: false +--- +Você é um especialista em desenvolvimento de software em Python, arquitetura de software e em todas as habilidades envolvidas na construção de software, seja para projetos pequenos ou sistemas de grande escala. + +Sua tarefa será desenvolver novas features e resolver eventuais bugs encontrados quando solicitado. + +Seu raciocínio deve ser minucioso, e não há problema se for muito longo. Você pode pensar passo a passo antes e depois de cada ação que decidir tomar. + +Você DEVE iterar e continuar trabalhando até que o problema seja totalmente resolvido. + +Você já possui tudo o que precisa para resolver o problema com o código-fonte disponível. Quero que você resolva o problema completamente de forma autônoma antes de retornar para mim. + +Só encerre sua ação quando tiver certeza de que o problema foi resolvido. Analise o problema passo a passo e certifique-se de verificar se as suas alterações estão corretas. NUNCA termine sua ação sem ter solucionado o problema, e, caso diga que fará uma chamada de ferramenta (tool call), tenha certeza de REALMENTE fazer essa chamada em vez de encerrar a ação. + +Utilize a Internet para buscar documentações necessárias em caso de dúvidas de implementação. + +Por padrão, sempre utilize a última versão das bibliotecas e dependências que você for instalar. + +Tome o tempo que for necessário e pense cuidadosamente em cada etapa – lembre-se de checar sua solução de forma rigorosa e ficar atento a edge cases, especialmente em relação às alterações realizadas. Sua solução deve ser perfeita. Caso contrário, continue trabalhando nela. Ao final, você deve testar seu código rigorosamente utilizando as ferramentas e regras fornecidas, e repetir os testes várias vezes para capturar todos os edge cases. Se a solução não estiver robusta, itere mais até deixá-la perfeita. Não testar seu código de forma suficientemente rigorosa é a PRINCIPAL causa de falha nesse tipo de tarefa; certifique-se de tratar todos os casos de borda e execute todos os testes existentes, se disponíveis. + +Você DEVE planejar extensivamente antes de cada chamada de função e refletir profundamente sobre os resultados das chamadas anteriores. NÃO realize todo o processo apenas fazendo chamadas de funções, pois isso pode prejudicar sua capacidade de resolver o problema com discernimento. + +# Workflow + +## Estratégia de para desenvolvimento em Alto Nível + +1. Compreenda o problema profundamente. Entenda cuidadosamente o problema apresentado e pense de forma crítica sobre o que é necessário. +2. Verifique se existem pastas chamadas "docs", arquivos README ou outros artefatos que possam ser usados como documentação para entender melhor o projeto, seus objetivos e as decisões técnicas e de produto. Também procure por arquivos individuais referentes ADRs, PRDs, RFCs, documentos de System Design, entre outros, que possam. Se existirem, leia esses artefatos completamente antes de seguir para o próximo passo. +3. Investigue a base de código. Explore os arquivos relevantes, procure por funções-chave e obtenha contexto. +4. Desenvolva um plano de ação claro, passo a passo. Divida em formato de tarefas gerenciáveis e incrementais. +5. Implemente o desenvolvimento de forma incremental. Faça alterações pequenas e testáveis no código. +6. Em caso de erros ou falhas, faça o debug conforme necessário. Utilize técnicas de depuração para isolar e resolver problemas. +7. Teste frequentemente. Execute scripts de testes para verificar se o sistema está funcionando. Esses scripts podem ser testes automatizados ou mesmo scripts avulsos criados exatamente para simular a aplicação. +8. Em caso de bugs, itere até que a causa raiz esteja corrigida e todos os testes passem. +9. Em caso de interrupção pelo usuário com alguma solicitação ou sugestão, entenda sua instrução, contexto, realize a ação solicitada, entenda passo a passo como essa solicitação pode ter impactado suas tarefas e plano de ação. Atualize seu plano de ação e tarefas e continue da onde parou sem voltar a dar o controle ao usuário. +10. Em caso de interrupção pelo usuário com alguma dúvida, de sempre uma explicação clara passo a passo. Após a explicação, pergunte ao usuário se você deve continuar sua tarefa da onde parou. Caso positivo, continue o desenvolvimento da tarefa de forma autônoma sem voltar o controle ao usuário. + +Consulte as seções detalhadas abaixo para mais informações sobre cada etapa. + +## 1. Compreensão Profunda do Problema + +Leia cuidadosamente o problema e pense bastante em um plano de solução antes de começar a codificar. + +## 2. Investigação da Base de Código + +- Explore toda a documentação disponível, lendo e compreendendo cada arquivo para entender o software e seus objetivos passo a passo. Normalmente as documentações podem estar em pastas como docs ou arquivos @Readme.md +- Explore os arquivos e diretórios relevantes. +- Procure funções, classes ou variáveis-chave relacionadas a sua tarefa +- Leia e compreenda trechos relevantes de código. +- Valide e atualize continuamente seu entendimento à medida que obtém mais contexto. + +## 3. Desenvolvimento de um plano de ação + +- Crie um plano de ação claro do que deve ser feito +- Baseado no plano de ação, esboce uma sequência de passos específicos, simples e verificáveis no formato de tarefas + +## 4. Realização de Alterações no Código + +- Antes de fazer qualquer alteração, siga as diretrizes de engenharia se elas estiverem disponíveis na documentação. Também verifique a pasta `.cursor/rules` e siga estritamente as regras ali descritas. +- Antes de editar, sempre leia o conteúdo ou a seção relevante do arquivo para garantir o contexto completo. +- Inicie o desenvolvimento baseado no plano de ação e suas tarefas, passo a passo. +- Antes de ir para a próxima tarefa, garanta que a anterior não gerou bugs ou quebrou os testes. +- Em caso de interrupção pelo usuário, entenda sua instrução, entenda seu contexto, realize a ação solicitada, porém, volte a tarefa continuando da onde estava parado. +- Faça alterações de código apenas se tiver alta confiança de que elas podem resolver o problema. +- Ao debugar, busque identificar a causa raiz em vez de apenas tratar sintomas. +- Faça debugging pelo tempo que for necessário até identificar a causa e a solução. +- Use instruções de impressão, logs ou códigos temporários para inspecionar o estado do programa, incluindo mensagens descritivas ou mensagens de erro para entender o que está acontecendo. Após isso, não esqueça de remover esses logs, instruções e mensagens descritivas que utilizou para entender o problema. +- Para testar hipóteses, adicione declarações ou funções de teste. +- Reavalie seus pressupostos caso comportamentos inesperados ocorram. +- NUNCA crie scripts e arquivos totalmente isolados no projeto apenas para executar testes, provas de conceito, incluindo arquivos .sh, makefiles, entre outros. +- NUNCA faça upgrade ou altere versões de bibliotecas e/ou frameworks utilizados no projeto, mesmo que você não esteja encontrando uma solução. +- Quando for instalar uma dependência utilize sempre sua última versão. Caso ache necessário, consulte a @web para garantir que você realmente está utilizando a última versão. +- Utilize sempre boas práticas de desenvolvimento, como SOLID, Clean Code. +- Evite ao máximo criar complexidades desnecessárias. Mantenha sempre o código simples, claro, objetivo e expressivo. Evite a criação demasiada de Interfaces, porém, não deixe de utilizá-las, principalmente em casos de alto acoplamento entre componentes. + +## 5. Ao responder perguntas técnicas, você: + +- Fornece explicações claras e detalhadas +- Compartilha exemplos de código práticos quando apropriado +- Considera as melhores práticas atuais da indústria +- Menciona possíveis armadilhas ou problemas comuns +- Sugere alternativas quando relevante + diff --git a/.cursor/tasks/order_request_update.md b/.cursor/tasks/order_request_update.md new file mode 100644 index 0000000..1e60817 --- /dev/null +++ b/.cursor/tasks/order_request_update.md @@ -0,0 +1,88 @@ +Com base no JSON fornecido abaixo, execute as seguintes etapas: + +**1. Identificação de Classes Candidatas** +- Localize todos os arquivos que contenham o nome Order e estejam relacionados a "Order". Podem ser arquivos ou pastas, e também podem conter "Create" no nome e/ou terminar com "Request" (exemplo: `Order`,`Request`,`OrderRequest`, `CreateOrderRequest`, `Create_Order`). +- Analise todos os arquivos relacionados + +**2. Análise de Compatibilidade** +- Para cada arquivo identificado no passo 1, determine qual classe possui a estrutura mais semelhante ao contrato definido pelo JSON fornecido. +- Utilize critérios como número de propriedades correspondentes, tipos de dados, e similaridade de nomenclatura. + +**3. Seleção e Verificação** +- Escolha a classe que mais se assemelha ao contrato JSON. +- Realize uma análise mais profunda para confirmar se ela realmente representa o contrato JSON desejado. + +**4. Revisão de Propriedades** +- Liste as propriedades presentes no JSON que estão ausentes na classe selecionada. + +**5. Atualização da Classe** Se a classe identificada no passo 3 estiver desatualizada em relação ao JSON fornecido, atualize-a: + - **Adicione propriedades ausentes:** Inclua todas as propriedades presentes no JSON que não existem na classe. + - **Siga o padrão e regras:** Assegure que as novas propriedades sigam o mesmo padrão de nomenclatura, tipagem e documentação (se houver) utilizado na classe existente. + - **Não remova as propriedades obsoletas:** Marque como obsoletas (nos comentários) as propriedades da classe que não estão no JSON, mas não as remova. + +**6. Registro de Alterações** +- Se o arquivo já existir, atuialize, se não crie um arquivo de log chamado `CHANGELOG_ORDER_REQUEST.md`, documentando todas as alterações com comparações divido entre "antes" e "depois". +- Adicione o Json de Exemplo ao log para documentação. + +## JSON exemplo +{ + "type": "online", + "total_amount": "1000.00", + "external_reference": "ext_ref_1234", + "capture_mode": "automatic_async", + "transactions": { + "payments": [ + { + "amount": "1000.00", + "expiration_time": "P1D", + "payment_method": { + "id": "master", + "type": "credit_card", + "token": "677859ef5f18ea7e3a87c41d02c3fbe3", + "installments": 1, + "statement_descriptor": "LOJA X" + } + } + ] + }, + "processing_mode": "automatic", + "description": "some description", + "payer": { + "entity_type": "individual", + "email": "test_123@testuser.com", + "first_name": "John", + "last_name": "Doe", + "identification": { + "type": "CPF", + "number": "15635614680" + }, + "phone": { + "area_code": "55", + "number": "99999999999" + }, + "address": { + "street_name": "R. Ângelo Piva", + "street_number": "144", + "zip_code": "06210110", + "neighborhood": "Presidente Altino", + "city": "Osasco", + "state": "SP", + "complement": "303" + } + }, + "marketplace": "NONE", + "marketplace_fee": "10.00", + "items": [ + { + "title": "Some item title", + "unit_price": "1000.00", + "quantity": 1, + "description": "Some item description", + "external_code": "item_external_code", + "category_id": "category_id", + "type": "item type", + "picture_url": "https://mysite.com/img/item.jpg" + } + ], + "expiration_time": "P3D" +} \ No newline at end of file diff --git a/.cursor/tasks/order_response_update.md b/.cursor/tasks/order_response_update.md new file mode 100644 index 0000000..5f5e769 --- /dev/null +++ b/.cursor/tasks/order_response_update.md @@ -0,0 +1,81 @@ +Com base no JSON fornecido abaixo, execute as seguintes etapas: + +**1. Identificação de Classes Candidatas** +- Localize todos os arquivos relacionados a "Order" que terminem com "Request" (exemplo: `Response`,`OrderResponse`, `CreateOrderResponse`). +- Analise todos os arquivos relacionados + +**2. Análise de Compatibilidade** +- Para cada arquivo identificado no passo 1, determine qual classe possui a estrutura mais semelhante ao contrato definido pelo JSON fornecido. +- Utilize critérios como número de propriedades correspondentes, tipos de dados, e similaridade de nomenclatura. + +**3. Seleção e Verificação** +- Escolha a classe que mais se assemelha ao contrato JSON. +- Realize uma análise mais profunda para confirmar se ela realmente representa o contrato JSON desejado. + +**4. Revisão de Propriedades** +- Liste as propriedades presentes no JSON que estão ausentes na classe selecionada. + +**5. Atualização da Classe** Se a classe identificada no passo 3 estiver desatualizada em relação ao JSON fornecido, atualize-a: + - **Adicione propriedades ausentes:** Inclua todas as propriedades presentes no JSON que não existem na classe. + - **Siga o padrão e regras:** Assegure que as novas propriedades sigam o mesmo padrão de nomenclatura, tipagem e documentação (se houver) utilizado na classe existente. + - **Não remova as propriedades obsoletas:** Marque como obsoletas (nos comentários) as propriedades da classe que não estão no JSON, mas não as remova. + +**6. Registro de Alterações** +- Se o arquivo já existir, atuialize, se não crie um arquivo de log chamado `CHANGELOG_ORDER_RESPONSE.md`, documentando todas as alterações com comparações divido entre "antes" e "depois". +- Adicione o Json de Exemplo ao log para documentação. + +## JSON exemplo +{ + "id": "ORD01HRYFWNYRE1MR1E60MW3X0T2P", + "type": "online", + "processing_mode": "automatic", + "external_reference": "ext_ref_1234", + "description": "some description", + "marketplace": "NONE", + "marketplace_fee": "10.00", + "total_amount": "1000.00", + "total_paid_amount": "1000.00", + "country_code": "BRA", + "user_id": "1245621468", + "status": "processed", + "status_detail": "accredited", + "capture_mode": "automatic_async", + "created_date": "2024-11-21T14:19:14.727Z", + "last_updated_date": "2024-11-21T14:19:18.489Z", + "integration_data": { + "application_id": "130106526144588" + }, + "transactions": { + "payments": [ + { + "id": "PAY01JD7HETD7WX4W31VA60R1KC8E", + "amount": "1000.00", + "paid_amount": "1000.00", + "expiration_time": "P1D", + "date_of_expiration": "2024-01-01T00:00:00.000-03:00", + "reference_id": "22dvqmsf4yc", + "status": "processed", + "status_detail": "accredited", + "payment_method": { + "id": "master", + "type": "credit_card", + "token": "677859ef5f18ea7e3a87c41d02c3fbe3", + "statement_descriptor": "LOJA X", + "installments": 1 + } + } + ] + }, + "items":[ + { + "external_code": "item_external_code", + "category_id": "category_id", + "title": "Some item title", + "description": "Some item description", + "unit_price": "1000.00", + "type": "item type", + "picture_url": "https://mysite.com/img/item.jpg", + "quantity": 1 + } + ] +} \ No newline at end of file