Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 31 additions & 8 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,51 @@ pip install santander-python-sdk
```python
from decimal import Decimal
from santander_sdk import SantanderApiClient, SantanderClientConfiguration
from santander_sdk.pix import transfer_pix_payment, get_transfer


# Setup do client
client = SantanderApiClient(SantanderClientConfiguration(
client_id="client_id",
client_secret="client_pk",
cert="certificate_path",
base_url="api_url"
base_url="api_url",
workspace_id="optional"
))

# Realizar um PIX para uma chave
# Exemplo 1 - PIX para uma chave (Telefone, email, chave aleatória, cpf ou cpnj)
transfer = transfer_pix_payment(
client,
pix_info="[email protected]", # PIX key
pix_key="[email protected]",
value=Decimal(0.99),
description="My first pix payment"
)

pix_info = get_transfer(transfer["id"])
# ...
```
# Exemplo 2 - Transferência pix via beneficiário:
benefiary = SantanderBeneficiary(
name="John Doe",
bankCode="404",
branch="2424",
number="123456789", # Número da conta com dígito verificador
type="CONTA_CORRENTE",
documentType="CPF",
documentNumber="12345678909",
)

transfer = transfer_pix_payment(
client,
benefiary,
value=Decimal(0.99),
description="My second pix payment by beneficiary"
)


## Em desenvolvimento
- Será atualizado o README
# Exemplo 3 - Consulta de um pix realizado
transfer = get_transfer(transfer["id"])
assert transfer["status"] == "PAYED"


```

## Funcionalidades

Expand Down
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ dynamic = ["version"]
description = "Client não oficial da API do Santander em Python"
authors = [
{ name = "Samuel Rodrigues Coelho", email = "[email protected]" },
{ name = "Erle Carrara", email = "[email protected]" },
{ name = "Walison Filipe", email = "[email protected]" },
]
readme = "README.md"
keywords = ["santander", "api", "client", "python"]
Expand Down
2 changes: 1 addition & 1 deletion santander_sdk/api_client/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ def convert_to_decimal(cents: int) -> Decimal:
return Decimal(cents) / 100


def document_type(document_number: str) -> str:
def document_type(document_number: str) -> Literal["CPF", "CNPJ"]:
if len(document_number) == 11:
return "CPF"
if len(document_number) == 14:
Expand Down
74 changes: 29 additions & 45 deletions santander_sdk/pix.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,12 @@
)

from santander_sdk.api_client.helpers import (
document_type,
get_pix_key_type,
retry_one_time_on_request_exception,
truncate_value,
)
from santander_sdk.types import (
BeneficiaryDataDict,
SantanderBeneficiary,
ConfirmOrderStatus,
CreateOrderStatus,
OrderStatus,
Expand All @@ -35,24 +34,17 @@
MAX_UPDATE_STATUS_ATTEMPTS_TO_CONFIRM = 120
PIX_CONFIRM_INTERVAL_TIME = 2

TYPE_ACCOUNT_MAP = {
"savings": "CONTA_POUPANCA",
"payment": "CONTA_PAGAMENTO",
"checking": "CONTA_CORRENTE",
}


def transfer_pix_payment(
client: SantanderApiClient,
pix_info: str | BeneficiaryDataDict,
pix_key: str | SantanderBeneficiary,
value: D,
description: str,
tags: list[str] = [],
) -> TransferPixResult:
"""Realiza uma transferência PIX para uma chave PIX ou para um beneficiário
- Se for informado uma chave PIX, o valor deve ser uma string com a chave CPF, CNPJ, EMAIL, CELULAR ou chave aleatória
- CELULAR deve ser informado no formato +5511912345678 (14 caracteres incluindo o +)
- Se for informado um beneficiário, o valor deve ser BeneficiaryDataDict com os dados do beneficiário
- Se for informado um beneficiário, o valor deve ser SantanderBeneficiary com os dados do beneficiário

### Retorno de sucesso:
- success: True se a transferência foi realizada com sucesso
Expand All @@ -69,7 +61,7 @@ def transfer_pix_payment(
)

create_pix_response = _request_create_pix_payment(
client, pix_info, value, description, tags
client, pix_key, value, description, tags
)
pix_id = create_pix_response.get("id")
logger.info("Santander - PIX criado com sucesso: {pix_id}")
Expand All @@ -94,6 +86,14 @@ def transfer_pix_payment(
return {"success": False, "error": error_message, "data": None}


def get_transfer(client: SantanderApiClient, pix_payment_id: str) -> SantanderPixResponse:
if not pix_payment_id:
raise SantanderValueErrorException("pix_payment_id não informado")

response = client.get(f"{PIX_ENDPOINT}/{pix_payment_id}")
return cast(SantanderPixResponse, response)


def _pix_payment_status_polling(
client: SantanderApiClient,
pix_id: str,
Expand Down Expand Up @@ -185,48 +185,32 @@ def _confirm_pix_payment(

def _request_create_pix_payment(
client: SantanderApiClient,
pix_info: BeneficiaryDataDict | str,
pix_key: SantanderBeneficiary | str,
value: D,
description: str,
tags: list[str] = [],
) -> SantanderPixResponse:
"""Cria uma ordem de pagamento. Caso o status seja REJECTED, a exceção SantanderRejectedTransactionException é lançada.
Regra de negócio aqui: pagamento por beneficiário na request deve ser informado o bank_code ou ispb, nunca os dois."""
"""Cria uma ordem de pagamento. Caso o status seja REJECTED, a exceção SantanderRejectedTransactionException é lançada."""
data = {
"tags": tags,
"paymentValue": truncate_value(value),
"remittanceInformation": description,
}
if isinstance(pix_info, str):
pix_type = get_pix_key_type(pix_info)
data.update({"dictCode": pix_info, "dictCodeType": pix_type})
elif isinstance(pix_info, dict):
try:
beneficiary = {
"branch": pix_info["bank_account"]["agencia"],
"number": f"{pix_info['bank_account']['conta']}{pix_info['bank_account']['conta_dv']}",
"type": TYPE_ACCOUNT_MAP[pix_info["bank_account"]["tipo_conta"]],
"documentType": document_type(
pix_info["bank_account"]["document_number"]
),
"documentNumber": pix_info["bank_account"]["document_number"],
"name": pix_info["recebedor"]["name"],
}
bank_account = pix_info["bank_account"]
bank_code = bank_account.get("bank_code_compe", "")
bank_ispb = bank_account.get("bank_code_ispb", "")
if bank_code:
beneficiary["bankCode"] = bank_code
elif bank_ispb:
beneficiary["ispb"] = bank_ispb
else:
raise SantanderValueErrorException("A chave de entrada é inválida")

data.update({"beneficiary": beneficiary})
except KeyError as e:
raise SantanderValueErrorException(
f"Campo obrigatório não informado para o beneficiário: {e}"
)
if isinstance(pix_key, str):
pix_type = get_pix_key_type(pix_key)
data.update({"dictCode": pix_key, "dictCodeType": pix_type})
elif isinstance(pix_key, dict):
beneficiary = cast(dict, pix_key.copy())
bank_code = pix_key.get("bankCode", "")
ispb = pix_key.get("ispb", "")

if bank_code and ispb:
"Deve ser informado o bankCode ou ispb, nunca os dois."
del beneficiary["ispb"]
elif not bank_code and not ispb:
raise SantanderValueErrorException("Deve ser informado 'bankCode' ou 'ispb'")

data.update({"beneficiary": beneficiary})
else:
raise SantanderValueErrorException("Chave PIX ou Beneficiário não informado")

Expand Down
25 changes: 2 additions & 23 deletions santander_sdk/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ class SantanderBeneficiary(TypedDict):
name: str
documentType: Literal["CPF", "CNPJ"]
documentNumber: str
bankCode: str
ispb: str
bankCode: str | None
ispb: str | None
branch: str
number: str
type: Literal["CONTA_CORRENTE", "CONTA_POUPANCA", "CONTA_PAGAMENTO"]
Expand Down Expand Up @@ -159,27 +159,6 @@ class SantanderTransferResponse(TypedDict):
beneficiary: SantanderBeneficiary | None


class BankAccountDict(TypedDict):
agencia: str
conta: str
conta_dv: str
tipo_conta: Literal["checking", "savings", "salary", "payment"]
document_number: str
bank_code_compe: str | None
bank_code_ispb: str | None


class ReceiverDataDict(BankAccountDict):
name: str


class BeneficiaryDataDict(TypedDict):
"""Dados do beneficiário para transferência PIX"""

"Dados do recebedor para transferência PIX"
bank_account: BankAccountDict
recebedor: ReceiverDataDict


SantanderPixResponse = SantanderTransferResponse | SantanderAPIErrorResponse

Expand Down
Loading