wip iugu
This commit is contained in:
@@ -19,9 +19,9 @@ app = APIGatewayHttpResolver(enable_validation=True)
|
||||
dyn = DynamoDBPersistenceLayer(ORDER_TABLE, dynamodb_client)
|
||||
|
||||
|
||||
@app.post('/')
|
||||
@app.post('/postback/<order_id>')
|
||||
@tracer.capture_method
|
||||
def postback():
|
||||
def postback(order_id: str):
|
||||
return Response(status_code=HTTPStatus.NO_CONTENT)
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,11 @@ ENROLLMENT_TABLE: str = os.getenv('ENROLLMENT_TABLE') # type: ignore
|
||||
|
||||
IUGU_ACCOUNT_ID: str = 'AF01CF1B3451459F92666F10589278EE'
|
||||
IUGU_API_TOKEN: str = os.getenv('IUGU_API_TOKEN') # type: ignore
|
||||
IUGU_TEST_MODE: bool = os.getenv('AWS_LAMBDA_FUNCTION_NAME') is None
|
||||
IUGU_POSTBACK_URL = 'https://zjg09ppxq8.execute-api.sa-east-1.amazonaws.com'
|
||||
|
||||
HTTP_CONNECT_TIMEOUT = int(os.environ.get('HTTP_CONNECT_TIMEOUT', 1))
|
||||
HTTP_READ_TIMEOUT = int(os.environ.get('HTTP_READ_TIMEOUT', 3))
|
||||
|
||||
BUCKET_NAME: str = os.getenv('BUCKET_NAME') # type: ignore
|
||||
|
||||
|
||||
@@ -12,7 +12,14 @@ from layercake.dateutils import now
|
||||
from layercake.dynamodb import DynamoDBPersistenceLayer, KeyPair
|
||||
|
||||
from boto3clients import dynamodb_client, s3_client
|
||||
from config import BILLING_TEMPLATE_URI, BUCKET_NAME, ORDER_TABLE, PAPERFORGE_API
|
||||
from config import (
|
||||
BILLING_TEMPLATE_URI,
|
||||
BUCKET_NAME,
|
||||
HTTP_CONNECT_TIMEOUT,
|
||||
HTTP_READ_TIMEOUT,
|
||||
ORDER_TABLE,
|
||||
PAPERFORGE_API,
|
||||
)
|
||||
|
||||
logger = Logger(__name__)
|
||||
order_layer = DynamoDBPersistenceLayer(ORDER_TABLE, dynamodb_client)
|
||||
@@ -50,7 +57,11 @@ def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool:
|
||||
|
||||
try:
|
||||
# Send template URI and data to Paperforge API to generate a PDF
|
||||
r = requests.post(PAPERFORGE_API, data=json_data, timeout=6)
|
||||
r = requests.post(
|
||||
PAPERFORGE_API,
|
||||
data=json_data,
|
||||
timeout=(HTTP_CONNECT_TIMEOUT, HTTP_READ_TIMEOUT),
|
||||
)
|
||||
r.raise_for_status()
|
||||
except requests.exceptions.Timeout:
|
||||
logger.info('The request timed out')
|
||||
|
||||
@@ -9,10 +9,18 @@ from layercake.dynamodb import (
|
||||
)
|
||||
|
||||
from boto3clients import dynamodb_client
|
||||
from config import ORDER_TABLE
|
||||
from config import IUGU_ACCOUNT_ID, IUGU_API_TOKEN, IUGU_TEST_MODE, ORDER_TABLE
|
||||
from iugu import Credentials, Iugu
|
||||
|
||||
logger = Logger(__name__)
|
||||
dyn = DynamoDBPersistenceLayer(ORDER_TABLE, dynamodb_client)
|
||||
iugu = Iugu(
|
||||
Credentials(
|
||||
IUGU_ACCOUNT_ID,
|
||||
IUGU_API_TOKEN,
|
||||
test_mode=IUGU_TEST_MODE,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@event_source(data_class=EventBridgeEvent)
|
||||
|
||||
@@ -4,27 +4,77 @@ from aws_lambda_powertools.utilities.data_classes import (
|
||||
event_source,
|
||||
)
|
||||
from aws_lambda_powertools.utilities.typing import LambdaContext
|
||||
from layercake.dateutils import now
|
||||
from layercake.dynamodb import (
|
||||
DynamoDBPersistenceLayer,
|
||||
SortKey,
|
||||
TransactKey,
|
||||
)
|
||||
|
||||
from boto3clients import dynamodb_client
|
||||
from config import ORDER_TABLE
|
||||
from config import (
|
||||
IUGU_ACCOUNT_ID,
|
||||
IUGU_API_TOKEN,
|
||||
IUGU_POSTBACK_URL,
|
||||
IUGU_TEST_MODE,
|
||||
ORDER_TABLE,
|
||||
)
|
||||
from iugu import Credentials, Iugu, Order
|
||||
|
||||
logger = Logger(__name__)
|
||||
dyn = DynamoDBPersistenceLayer(ORDER_TABLE, dynamodb_client)
|
||||
iugu = Iugu(
|
||||
Credentials(
|
||||
IUGU_ACCOUNT_ID,
|
||||
IUGU_API_TOKEN,
|
||||
test_mode=IUGU_TEST_MODE,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@event_source(data_class=EventBridgeEvent)
|
||||
@logger.inject_lambda_context
|
||||
def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool:
|
||||
new_image = event.detail['new_image']
|
||||
now_ = now()
|
||||
order_id = new_image['id']
|
||||
r = dyn.collection.get_items(
|
||||
TransactKey(order_id)
|
||||
+ SortKey('ADDRESS', rename_key='address')
|
||||
+ SortKey('ITEMS', path_spec='items', rename_key='items'),
|
||||
flatten_top=False,
|
||||
)
|
||||
|
||||
doc = {
|
||||
'id': order_id,
|
||||
'sk': 'IUGU',
|
||||
'invoice_id': '',
|
||||
}
|
||||
payment_method = new_image['payment_method']
|
||||
is_pix = payment_method == 'PIX'
|
||||
is_bank_slip = payment_method == 'BANK_SLIP'
|
||||
|
||||
invoice = iugu.create_invoice(
|
||||
order=Order(
|
||||
address=r.get('address', {}),
|
||||
items=r.get('items', []),
|
||||
**new_image,
|
||||
),
|
||||
postback_url=f'{IUGU_POSTBACK_URL}/postback/{order_id}',
|
||||
)
|
||||
|
||||
try:
|
||||
dyn.put_item(
|
||||
item={
|
||||
'id': order_id,
|
||||
'sk': 'INVOICE',
|
||||
'payment_method': payment_method,
|
||||
'secure_id': invoice['secure_id'],
|
||||
'secure_url': invoice['secure_url'],
|
||||
'created_at': now_,
|
||||
# Uncomment this when adding for multiple payment providers
|
||||
# 'payment_provider': 'iugu',
|
||||
}
|
||||
| ({'bank_slip': invoice['bank_slip']} if is_bank_slip else {})
|
||||
| ({'pix': invoice['pix']} if is_pix else {}),
|
||||
cond_expr='attribute_not_exists(sk)',
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return True
|
||||
|
||||
@@ -15,6 +15,7 @@ Documentation:
|
||||
- https://support.iugu.com/hc/pt-br/articles/212456346-Usar-cart%C3%B5es-de-teste-em-modo-de-teste
|
||||
"""
|
||||
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
@@ -24,7 +25,10 @@ from urllib.parse import ParseResult, urlparse
|
||||
import requests
|
||||
from aws_lambda_powertools import Logger
|
||||
from layercake.extra_types import CreditCard
|
||||
from pydantic import BaseModel, ConfigDict, HttpUrl
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
|
||||
HTTP_CONNECT_TIMEOUT = int(os.environ.get('HTTP_CONNECT_TIMEOUT', 1))
|
||||
HTTP_READ_TIMEOUT = int(os.environ.get('HTTP_READ_TIMEOUT', 3))
|
||||
|
||||
logger = Logger(__name__)
|
||||
|
||||
@@ -71,16 +75,6 @@ class Order(BaseModel):
|
||||
cnpj: str | None = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class Invoice: ...
|
||||
|
||||
|
||||
@dataclass
|
||||
class BankSlip(BaseModel):
|
||||
digitable_line: str
|
||||
bank_slip_url: HttpUrl
|
||||
|
||||
|
||||
@dataclass
|
||||
class Credentials:
|
||||
account_id: str
|
||||
@@ -88,17 +82,6 @@ class Credentials:
|
||||
test_mode: bool = True
|
||||
|
||||
|
||||
@dataclass
|
||||
class Token(str):
|
||||
id: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class Transaction:
|
||||
status: Status
|
||||
response: dict
|
||||
|
||||
|
||||
class Iugu:
|
||||
base_url: ParseResult = urlparse('https://api.iugu.com')
|
||||
|
||||
@@ -114,7 +97,7 @@ class Iugu:
|
||||
self,
|
||||
order: Order,
|
||||
postback_url: ParseResult | str,
|
||||
) -> Invoice:
|
||||
) -> dict:
|
||||
"""
|
||||
O que é uma fatura?
|
||||
-------------------
|
||||
@@ -127,6 +110,8 @@ class Iugu:
|
||||
No response dessa chamada é retornado uma url na propriedade secure_url,
|
||||
onde o cliente final pode acessar e efetuar o pagamento em um checkout da
|
||||
IUGU.
|
||||
|
||||
- https://dev.iugu.com/reference/criar-fatura
|
||||
"""
|
||||
|
||||
url = self.url(path='/v1/invoices')
|
||||
@@ -168,33 +153,25 @@ class Iugu:
|
||||
}
|
||||
|
||||
try:
|
||||
r = requests.post(url, json=payload, timeout=15)
|
||||
r = requests.post(
|
||||
url, json=payload, timeout=(HTTP_CONNECT_TIMEOUT, HTTP_READ_TIMEOUT)
|
||||
)
|
||||
r.raise_for_status()
|
||||
except requests.HTTPError as err:
|
||||
logger.exception(err)
|
||||
raise
|
||||
else:
|
||||
return r.json()
|
||||
# pix = (
|
||||
# Pix(**response['pix'])
|
||||
# if order.payment_method == PaymentMethod.PIX
|
||||
# else None
|
||||
# )
|
||||
# bank_slip = (
|
||||
# BankSlip(**response['bank_slip'])
|
||||
# if order.payment_method == PaymentMethod.BANK_SLIP
|
||||
# else None
|
||||
# )
|
||||
|
||||
# return Invoice(
|
||||
# id=response['secure_id'],
|
||||
# pdf=bank_slip.bank_slip_url
|
||||
# if bank_slip
|
||||
# else '%s.pdf' % response['secure_url'],
|
||||
# pix=pix,
|
||||
# )
|
||||
def payment_token(self, credit_card: CreditCard) -> dict:
|
||||
"""When creating a invoice, it can't make the charge immediately the invoice.
|
||||
It's necessary make have a token (payment token) to charge.
|
||||
|
||||
Payment token doesn't depends an invoice, just a credit card to charge later.
|
||||
|
||||
- https://dev.iugu.com/reference/criar-token
|
||||
"""
|
||||
|
||||
def payment_token(self, credit_card: CreditCard) -> Token:
|
||||
url = self.url(path='/v1/payment_token')
|
||||
|
||||
try:
|
||||
@@ -213,21 +190,21 @@ class Iugu:
|
||||
'year': credit_card.exp_year,
|
||||
},
|
||||
},
|
||||
timeout=15,
|
||||
timeout=(HTTP_CONNECT_TIMEOUT, HTTP_READ_TIMEOUT),
|
||||
)
|
||||
r.raise_for_status()
|
||||
except requests.HTTPError as err:
|
||||
logger.exception(err)
|
||||
raise
|
||||
else:
|
||||
return Token(r.json()['id'])
|
||||
return r.json()
|
||||
|
||||
def charge(
|
||||
self,
|
||||
invoice_id: str,
|
||||
token: Token,
|
||||
token: str,
|
||||
installments: int = 1,
|
||||
) -> Transaction:
|
||||
) -> dict:
|
||||
"""
|
||||
O que é Cobrança Direta
|
||||
-----------------------
|
||||
@@ -240,6 +217,8 @@ class Iugu:
|
||||
e o token gerado para o cartão de crédito (iugu js).
|
||||
Se o seu intuito é gerar apenas um boleto, essa chamada também retorna
|
||||
o PDF do boleto e o link de pagamento para efetuar o pagamento.
|
||||
|
||||
- https://dev.iugu.com/reference/cobranca-direta
|
||||
"""
|
||||
|
||||
url = self.url(path='/v1/charge')
|
||||
@@ -250,24 +229,21 @@ class Iugu:
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(url, json=payload, timeout=15)
|
||||
response.raise_for_status()
|
||||
r = requests.post(
|
||||
url, json=payload, timeout=(HTTP_CONNECT_TIMEOUT, HTTP_READ_TIMEOUT)
|
||||
)
|
||||
r.raise_for_status()
|
||||
except requests.HTTPError as err:
|
||||
logger.exception(err)
|
||||
raise
|
||||
else:
|
||||
success = response.json()['success']
|
||||
|
||||
return Transaction(
|
||||
status=Status.PAID if success else Status.DECLINED,
|
||||
response=response.json(),
|
||||
)
|
||||
return r.json()
|
||||
|
||||
def get_invoice(self, invoice_id: str) -> dict:
|
||||
url = self.url(path=f'/v1/invoices/{format_id(invoice_id)}')
|
||||
|
||||
try:
|
||||
r = requests.get(url, timeout=15)
|
||||
r = requests.get(url, timeout=(HTTP_CONNECT_TIMEOUT, HTTP_READ_TIMEOUT))
|
||||
r.raise_for_status()
|
||||
except requests.HTTPError as err:
|
||||
logger.exception(err)
|
||||
|
||||
Reference in New Issue
Block a user