WIP
This commit is contained in:
@@ -13,6 +13,7 @@ from aws_lambda_powertools.logging import correlation_paths
|
||||
from aws_lambda_powertools.utilities.typing import LambdaContext
|
||||
from layercake.dateutils import now
|
||||
from layercake.dynamodb import DynamoDBPersistenceLayer, KeyPair
|
||||
from layercake.funcs import pick
|
||||
|
||||
from boto3clients import dynamodb_client
|
||||
from config import ORDER_TABLE
|
||||
@@ -29,10 +30,12 @@ class OrderNotFoundError(NotFoundError): ...
|
||||
class InvoiceNotFoundError(NotFoundError): ...
|
||||
|
||||
|
||||
class StatusAttr(Enum):
|
||||
# Post-migration (orders): uncomment the following lines
|
||||
class StatusTimestampAttr(Enum):
|
||||
# Post-migration (orders): uncomment the following 2 lines
|
||||
# PAID = 'paid_at'
|
||||
# EXTERNALLY_PAID = 'paid_at'
|
||||
|
||||
# Post-migration (orders): remove the following 2 lines
|
||||
EXTERNALLY_PAID = 'payment_date'
|
||||
PAID = 'payment_date'
|
||||
|
||||
@@ -41,19 +44,24 @@ class StatusAttr(Enum):
|
||||
EXPIRED = 'expired_at'
|
||||
|
||||
|
||||
def _status_attr(status: str) -> StatusAttr | None:
|
||||
def _timestamp_attr_for_status(status: str) -> str | None:
|
||||
try:
|
||||
return StatusAttr[status]
|
||||
return StatusTimestampAttr[status].value
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
|
||||
def _friendly_status(status: str) -> str:
|
||||
if 'status' == 'EXTERNALLY_PAID':
|
||||
if status == 'EXTERNALLY_PAID':
|
||||
return 'PAID'
|
||||
return status
|
||||
|
||||
|
||||
def _get_order_owner(order_id: str) -> dict:
|
||||
r = dyn.get_item(KeyPair(order_id, '0'))
|
||||
return pick(('user_id', 'org_id'), r)
|
||||
|
||||
|
||||
@app.post('/<order_id>/postback')
|
||||
@tracer.capture_method
|
||||
def postback(order_id: str):
|
||||
@@ -62,31 +70,33 @@ def postback(order_id: str):
|
||||
|
||||
now_ = now()
|
||||
event = decoded_body['event']
|
||||
status = decoded_body.get('data[status]', '').upper()
|
||||
status_attr = _status_attr(status)
|
||||
raw_status = decoded_body.get('data[status]', '').upper()
|
||||
status = _friendly_status(raw_status)
|
||||
timestamp_attr = _timestamp_attr_for_status(raw_status)
|
||||
|
||||
if event != 'invoice.status_changed' or not status_attr:
|
||||
return Response(status_code=HTTPStatus.NO_CONTENT)
|
||||
if event != 'invoice.status_changed' or not timestamp_attr:
|
||||
logger.debug('Event not acceptable', order_id=order_id)
|
||||
return Response(status_code=HTTPStatus.NOT_ACCEPTABLE)
|
||||
|
||||
with dyn.transact_writer() as transact:
|
||||
transact.update(
|
||||
key=KeyPair(order_id, '0'),
|
||||
update_expr='SET #status = :status, \
|
||||
#status_attr = :now, \
|
||||
#ts_attr = :now, \
|
||||
updated_at = :now',
|
||||
cond_expr='attribute_exists(sk)',
|
||||
expr_attr_names={
|
||||
'#status': 'status',
|
||||
'#status_attr': status_attr.value,
|
||||
'#ts_attr': timestamp_attr,
|
||||
},
|
||||
expr_attr_values={
|
||||
':status': _friendly_status(status),
|
||||
':status': status,
|
||||
':now': now_,
|
||||
},
|
||||
exc_cls=OrderNotFoundError,
|
||||
)
|
||||
|
||||
if status == 'EXTERNALLY_PAID':
|
||||
if raw_status == 'EXTERNALLY_PAID':
|
||||
transact.update(
|
||||
key=KeyPair(order_id, 'INVOICE'),
|
||||
cond_expr='attribute_exists(sk)',
|
||||
@@ -99,6 +109,51 @@ def postback(order_id: str):
|
||||
exc_cls=InvoiceNotFoundError,
|
||||
)
|
||||
|
||||
if status == 'PAID':
|
||||
try:
|
||||
dyn.put_item(
|
||||
item={
|
||||
'id': order_id,
|
||||
'sk': 'FULFILLMENT',
|
||||
'status': 'IN_PROGRESS',
|
||||
'created_at': now_,
|
||||
**_get_order_owner(order_id),
|
||||
},
|
||||
cond_expr='attribute_not_exists(sk)',
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if status in ('CANCELED', 'REFUNDED'):
|
||||
try:
|
||||
with dyn.transact_writer() as transact:
|
||||
transact.condition(
|
||||
key=KeyPair(order_id, 'FULFILLMENT'),
|
||||
cond_expr=(
|
||||
'attribute_exists(sk) '
|
||||
'AND #status <> :in_progress '
|
||||
'AND #status <> :rollback'
|
||||
),
|
||||
expr_attr_names={
|
||||
'#status': 'status',
|
||||
},
|
||||
expr_attr_values={
|
||||
':in_progress': 'IN_PROGRESS',
|
||||
':rollback': 'ROLLBACK',
|
||||
},
|
||||
)
|
||||
transact.put(
|
||||
item={
|
||||
'id': order_id,
|
||||
'sk': 'FULFILLMENT#ROLLBACK',
|
||||
'created_at': now_,
|
||||
},
|
||||
cond_expr='attribute_not_exists(sk)',
|
||||
)
|
||||
logger.debug('Fulfillment rollback event created', order_id=order_id)
|
||||
except Exception:
|
||||
logger.debug('Fulfillment rollback event already exists', order_id=order_id)
|
||||
|
||||
return Response(status_code=HTTPStatus.NO_CONTENT)
|
||||
|
||||
|
||||
|
||||
@@ -90,6 +90,8 @@ def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool:
|
||||
item={
|
||||
'id': pk,
|
||||
'sk': f'{sk}#SCHEDULE#AUTO_CLOSE',
|
||||
# Post-migration: uncomment the following line
|
||||
# 'sk': f'{sk}#SCHEDULED#AUTO_CLOSE',
|
||||
'ttl': ttl(
|
||||
start_dt=datetime.combine(end_period, time())
|
||||
+ timedelta(days=1)
|
||||
|
||||
@@ -80,10 +80,7 @@ def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool:
|
||||
cond_expr='attribute_not_exists(sk)',
|
||||
)
|
||||
except Exception as exc:
|
||||
logger.exception(
|
||||
exc,
|
||||
keypair={'id': pk, 'sk': sk},
|
||||
)
|
||||
logger.exception(exc, keypair={'id': pk, 'sk': sk})
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
@@ -107,8 +107,8 @@ def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool:
|
||||
transact.put(
|
||||
item={
|
||||
'id': order_id,
|
||||
'sk': 'SCHEDULE#SELF_DESTRUCTION',
|
||||
'ttl': ttl(start_dt=now_, days=14),
|
||||
'sk': 'SCHEDULED#SELF_DESTRUCTION',
|
||||
'ttl': ttl(start_dt=now_, days=7),
|
||||
'created_at': now_,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -23,7 +23,11 @@ def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool:
|
||||
order_id = keys['id']
|
||||
|
||||
r = dyn.collection.query(PartitionKey(order_id), limit=150)
|
||||
logger.info('Records found', total_items=len(r['items']), records=r['items'])
|
||||
logger.info(
|
||||
msg='Records found',
|
||||
total_items=len(r['items']),
|
||||
records=r['items'],
|
||||
)
|
||||
|
||||
with dyn.batch_writer() as batch:
|
||||
for pair in r['items']:
|
||||
|
||||
78
orders-events/app/events/start_fulfillment.py
Normal file
78
orders-events/app/events/start_fulfillment.py
Normal file
@@ -0,0 +1,78 @@
|
||||
import pprint
|
||||
from dataclasses import asdict, dataclass
|
||||
from uuid import uuid4
|
||||
|
||||
from aws_lambda_powertools import Logger
|
||||
from aws_lambda_powertools.utilities.data_classes import (
|
||||
EventBridgeEvent,
|
||||
event_source,
|
||||
)
|
||||
from aws_lambda_powertools.utilities.typing import LambdaContext
|
||||
from layercake.dynamodb import DynamoDBPersistenceLayer, KeyChain, KeyPair
|
||||
|
||||
from boto3clients import dynamodb_client
|
||||
from config import ENROLLMENT_TABLE
|
||||
|
||||
logger = Logger(__name__)
|
||||
dyn = DynamoDBPersistenceLayer(ENROLLMENT_TABLE, dynamodb_client)
|
||||
|
||||
|
||||
@event_source(data_class=EventBridgeEvent)
|
||||
@logger.inject_lambda_context
|
||||
def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool:
|
||||
new_image = event.detail['new_image']
|
||||
order_id = new_image['id']
|
||||
enrollments = dyn.collection.query(
|
||||
key=KeyPair(order_id, 'ENROLLMENT#'),
|
||||
).get('items', [])
|
||||
|
||||
if not enrollments:
|
||||
items = dyn.collection.get_item(
|
||||
KeyPair(order_id, 'ITEMS'),
|
||||
raise_on_error=False,
|
||||
default=[],
|
||||
)
|
||||
pprint.pp(items)
|
||||
# docx = {
|
||||
# 'id': f'SEAT#ORG#{org_id}',
|
||||
# 'sk': f'ORDER#{order_id}#ENROLLMENT#{uuid4()}',
|
||||
# 'course': {},
|
||||
# 'created_at': now_,
|
||||
# }
|
||||
|
||||
pprint.pp(enrollments)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
# Se houver matriculas
|
||||
# -> com: scheduled_for
|
||||
# -> tenta agendar, se não joga para vagas
|
||||
# -> tenta matriculas, se falhar, joga para vagas
|
||||
|
||||
# se não houver vagas, gera as vagas.
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Course:
|
||||
id: str
|
||||
name: str
|
||||
access_period: int
|
||||
|
||||
|
||||
def _get_courses(ids: set) -> tuple[Course, ...]:
|
||||
pairs = tuple(KeyPair(idx, '0') for idx in ids)
|
||||
r = dyn.collection.get_items(
|
||||
KeyChain(pairs),
|
||||
flatten_top=False,
|
||||
)
|
||||
courses = tuple(
|
||||
Course(
|
||||
id=idx,
|
||||
name=obj['name'],
|
||||
access_period=obj['access_period'],
|
||||
)
|
||||
for idx, obj in r.items()
|
||||
)
|
||||
|
||||
return courses
|
||||
@@ -17,7 +17,7 @@ dev = [
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
pythonpath = ["app/"]
|
||||
addopts = "--cov --cov-report html -v"
|
||||
addopts = "--cov=app --cov-report html"
|
||||
|
||||
[tool.ruff]
|
||||
target-version = "py311"
|
||||
|
||||
@@ -21,12 +21,12 @@ Parameters:
|
||||
Globals:
|
||||
Function:
|
||||
CodeUri: app/
|
||||
Runtime: python3.13
|
||||
Runtime: python3.14
|
||||
Tracing: Active
|
||||
Architectures:
|
||||
- x86_64
|
||||
Layers:
|
||||
- !Sub arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:layer:layercake:104
|
||||
- !Sub arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:layer:layercake:106
|
||||
Environment:
|
||||
Variables:
|
||||
TZ: America/Sao_Paulo
|
||||
@@ -189,7 +189,7 @@ Resources:
|
||||
Type: AWS::Serverless::Function
|
||||
Properties:
|
||||
Handler: events.billing.close_window.lambda_handler
|
||||
Timeout: 12
|
||||
Timeout: 30
|
||||
LoggingConfig:
|
||||
LogGroup: !Ref EventLog
|
||||
Policies:
|
||||
@@ -209,6 +209,8 @@ Resources:
|
||||
id:
|
||||
- prefix: BILLING
|
||||
sk:
|
||||
# Post-migration: uncomment the following line
|
||||
# - suffix: SCHEDULED#AUTO_CLOSE
|
||||
- suffix: SCHEDULE#AUTO_CLOSE
|
||||
|
||||
EventBillingSendEmailOnClosingFunction:
|
||||
@@ -247,10 +249,39 @@ Resources:
|
||||
old_image:
|
||||
status: [PENDING]
|
||||
|
||||
EventStartFulfillmentFunction:
|
||||
Type: AWS::Serverless::Function
|
||||
Properties:
|
||||
Handler: events.start_fulfillment.lambda_handler
|
||||
Timeout: 30
|
||||
LoggingConfig:
|
||||
LogGroup: !Ref EventLog
|
||||
Policies:
|
||||
- DynamoDBCrudPolicy:
|
||||
TableName: !Ref OrderTable
|
||||
- DynamoDBCrudPolicy:
|
||||
TableName: !Ref EnrollmentTable
|
||||
- DynamoDBReadPolicy:
|
||||
TableName: !Ref CourseTable
|
||||
Events:
|
||||
DynamoDBEvent:
|
||||
Type: EventBridgeRule
|
||||
Properties:
|
||||
Pattern:
|
||||
resources: [!Ref OrderTable]
|
||||
detail-type: [INSERT]
|
||||
detail:
|
||||
new_image:
|
||||
sk: [FULFILLMENT]
|
||||
status: [IN_PROGRESS]
|
||||
org_id:
|
||||
- exists: true
|
||||
|
||||
EventRunSelfDestructionFunction:
|
||||
Type: AWS::Serverless::Function
|
||||
Properties:
|
||||
Handler: events.run_self_destruction.lambda_handler
|
||||
Timeout: 30
|
||||
LoggingConfig:
|
||||
LogGroup: !Ref EventLog
|
||||
Policies:
|
||||
@@ -265,7 +296,7 @@ Resources:
|
||||
detail-type: [EXPIRE]
|
||||
detail:
|
||||
keys:
|
||||
sk: ['SCHEDULE#SELF_DESTRUCTION']
|
||||
sk: ['SCHEDULED#SELF_DESTRUCTION']
|
||||
|
||||
# DEPRECATED
|
||||
EventAppendOrgIdFunction:
|
||||
@@ -322,6 +353,7 @@ Resources:
|
||||
user_id:
|
||||
- exists: false
|
||||
|
||||
# DEPRECATED
|
||||
EventRemoveSlotsIfCanceledFunction:
|
||||
Type: AWS::Serverless::Function
|
||||
Properties:
|
||||
|
||||
@@ -2,6 +2,7 @@ import base64
|
||||
import json
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
from decimal import Decimal
|
||||
from http import HTTPMethod
|
||||
from urllib.parse import urlencode
|
||||
|
||||
@@ -155,7 +156,10 @@ def dynamodb_persistence_layer(dynamodb_client):
|
||||
@pytest.fixture()
|
||||
def dynamodb_seeds(dynamodb_persistence_layer):
|
||||
with open('tests/seeds.jsonl', 'rb') as fp:
|
||||
reader = jsonlines.Reader(fp)
|
||||
reader = jsonlines.Reader(
|
||||
fp,
|
||||
loads=lambda s: json.loads(s, parse_float=Decimal), # type: ignore
|
||||
)
|
||||
|
||||
for line in reader.iter(type=dict, skip_invalid=True):
|
||||
dynamodb_persistence_layer.put_item(item=line)
|
||||
|
||||
42
orders-events/tests/events/test_start_fulfillment.py
Normal file
42
orders-events/tests/events/test_start_fulfillment.py
Normal file
@@ -0,0 +1,42 @@
|
||||
from aws_lambda_powertools.utilities.typing import LambdaContext
|
||||
from layercake.dynamodb import DynamoDBPersistenceLayer
|
||||
|
||||
import events.start_fulfillment as app
|
||||
|
||||
|
||||
def test_fulfillment_enrollments(
|
||||
dynamodb_seeds,
|
||||
dynamodb_persistence_layer: DynamoDBPersistenceLayer,
|
||||
lambda_context: LambdaContext,
|
||||
):
|
||||
event = {
|
||||
'detail': {
|
||||
'new_image': {
|
||||
'id': '9b9441d2-4ae3-4b50-8cb6-71e872d4492a',
|
||||
'sk': 'FULFILLMENT',
|
||||
'org_id': 'cJtK9SsnJhKPyxESe7g3DG',
|
||||
'status': 'IN_PROGRESS',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert app.lambda_handler(event, lambda_context) # type: ignore
|
||||
|
||||
|
||||
def test_fulfillment_items(
|
||||
dynamodb_seeds,
|
||||
dynamodb_persistence_layer: DynamoDBPersistenceLayer,
|
||||
lambda_context: LambdaContext,
|
||||
):
|
||||
event = {
|
||||
'detail': {
|
||||
'new_image': {
|
||||
'id': '9f7fa055-7c0b-418a-b023-77477d1895b9',
|
||||
'sk': 'FULFILLMENT',
|
||||
'org_id': 'cJtK9SsnJhKPyxESe7g3DG',
|
||||
'status': 'IN_PROGRESS',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert app.lambda_handler(event, lambda_context) # type: ignore
|
||||
@@ -10,9 +10,18 @@
|
||||
{"id": "6a60d026-d383-4707-b093-b6eddea1a24e", "sk": "ITEMS", "items": [{"id": "a810dd22-56c0-4d9b-8cd2-7e2ee9c45839", "name": "pytest", "quantity": 1, "unit_price": 109}]}
|
||||
{"id": "a810dd22-56c0-4d9b-8cd2-7e2ee9c45839", "sk": "metadata#betaeducacao", "course_id": "dc1a0428-47bf-4db1-a5da-24be49c9fda6", "create_date": "2025-06-05T12:13:54.371416+00:00"}
|
||||
|
||||
{"id": "2849f1d5-f4f1-411e-8497-ec3a40afc0ab", "sk": "0" "payment_method": "BANK_SLIP", "status": "PENDING", "total": 178.2, "due_date": "", "email": "org+15608435000190@users.noreply.saladeaula.digital", "name": "Beta Educação", "coupon": "10OFF", "discount": -19.8, "create_date": "2026-01-07T19:09:54.193859-03:00", "updated_at": "2026-01-07T19:09:54.871374-03:00", "org_id": "cJtK9SsnJhKPyxESe7g3DG", "subtotal": 198, "tenant_id": "cJtK9SsnJhKPyxESe7g3DG", "cnpj": "15608435000190"}
|
||||
{"id": "2849f1d5-f4f1-411e-8497-ec3a40afc0ab", "sk": "0", "payment_method": "BANK_SLIP", "status": "PENDING", "total": 178.2, "due_date": "", "email": "org+15608435000190@users.noreply.saladeaula.digital", "name": "Beta Educação", "coupon": "10OFF", "discount": -19.8, "create_date": "2026-01-07T19:09:54.193859-03:00", "updated_at": "2026-01-07T19:09:54.871374-03:00", "org_id": "cJtK9SsnJhKPyxESe7g3DG", "subtotal": 198, "tenant_id": "cJtK9SsnJhKPyxESe7g3DG", "cnpj": "15608435000190"}
|
||||
{"id": "2849f1d5-f4f1-411e-8497-ec3a40afc0ab", "sk": "ITEMS", "items": [ { "name": "CIPA Grau de Risco 1", "id": "3c27ea9c-9464-46a1-9717-8c1441793186", "quantity": 1, "unit_price": 99 }, { "name": "CIPA Grau de Risco 2", "id": "99bb3b60-4ded-4a8e-937c-ba2d78ec6454", "quantity": 1, "unit_price": 99 } ], "created_at": "2026-01-07T19:09:54.193859-03:00"}
|
||||
{"id": "2849f1d5-f4f1-411e-8497-ec3a40afc0ab", "sk": "ADDRESS", "city": "São José", "postcode": "88101001", "state": "SC", "created_at": "2026-01-07T19:09:54.193859-03:00", "address1": "Avenida Presidente Kennedy" "address2": "", "neighborhood": "Campinas"}
|
||||
{"id": "2849f1d5-f4f1-411e-8497-ec3a40afc0ab", "sk": "ADDRESS", "city": "São José", "postcode": "88101001", "state": "SC", "created_at": "2026-01-07T19:09:54.193859-03:00", "address1": "Avenida Presidente Kennedy", "address2": "", "neighborhood": "Campinas"}
|
||||
|
||||
// Seeds for Order
|
||||
// file: tests/events/test_start_fulfillment.py
|
||||
{"id": "9b9441d2-4ae3-4b50-8cb6-71e872d4492a", "sk": "ITEMS", "items": [ { "name": "Combate a Incêndio", "id": "4866c068-577a-45b0-b41a-41a7dc6b9ab7", "quantity": 2, "unit_price": 99 } ], "created_at": "2026-01-20T13:05:52.737256-03:00"}
|
||||
{"id": "9b9441d2-4ae3-4b50-8cb6-71e872d4492a", "sk": "ENROLLMENT#7d3f5457-8533-4f27-a0a4-ffa209a93f7d", "course": { "name": "Combate a Incêndio", "id": "4866c068-577a-45b0-b41a-41a7dc6b9ab7", "access_period": 365 }, "user": { "name": "Maitê L Siqueira", "cpf": "02186829991", "id": "87606a7f-de56-4198-a91d-b6967499d382", "email": "osergiosiqueira+maite@gmail.com" }, "created_at": "2026-01-20T13:05:52.737256-03:00", "status": "PENDING"}
|
||||
{"id": "9b9441d2-4ae3-4b50-8cb6-71e872d4492a", "sk": "ENROLLMENT#9576855e-b259-4f3e-8315-1612a5cb8c36", "user": { "name": "Sérgio Rafael de Siqueira", "cpf": "07879819908", "id": "5OxmMjL-ujoR5IMGegQz", "email": "sergio@somosbeta.com.br" }, "course": { "name": "Combate a Incêndio", "id": "4866c068-577a-45b0-b41a-41a7dc6b9ab7", "access_period": 365 }, "created_at": "2026-01-20T13:05:52.737256-03:00", "status": "PENDING"}
|
||||
// Seeds for Order
|
||||
{"id": "9f7fa055-7c0b-418a-b023-77477d1895b9", "sk": "ITEMS", "items": [ { "name": "Combate a Incêndio", "id": "4866c068-577a-45b0-b41a-41a7dc6b9ab7", "quantity": 2, "unit_price": 99 } ], "created_at": "2026-01-20T13:05:52.737256-03:00"}
|
||||
|
||||
|
||||
// Seeds for Iugu
|
||||
// file: tests/test_app.py
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from http import HTTPMethod, HTTPStatus
|
||||
|
||||
from layercake.dynamodb import DynamoDBPersistenceLayer, KeyPair
|
||||
from layercake.dynamodb import DynamoDBPersistenceLayer, SortKey, TransactKey
|
||||
|
||||
from .conftest import HttpApiProxy, LambdaContext
|
||||
|
||||
@@ -36,6 +36,11 @@ def test_postback(
|
||||
)
|
||||
assert r['statusCode'] == HTTPStatus.NO_CONTENT
|
||||
|
||||
order = dynamodb_persistence_layer.get_item(KeyPair(order_id, '0'))
|
||||
order = dynamodb_persistence_layer.collection.get_items(
|
||||
TransactKey(order_id)
|
||||
+ SortKey('0')
|
||||
+ SortKey('FULFILLMENT', rename_key='fulfillment')
|
||||
)
|
||||
assert 'fulfillment' in order
|
||||
|
||||
assert order['status'] == 'PAID'
|
||||
|
||||
18
orders-events/uv.lock
generated
18
orders-events/uv.lock
generated
@@ -62,6 +62,18 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/54/51/321e821856452f7386c4e9df866f196720b1ad0c5ea1623ea7399969ae3b/authlib-1.6.6-py2.py3-none-any.whl", hash = "sha256:7d9e9bc535c13974313a87f53e8430eb6ea3d1cf6ae4f6efcd793f2e949143fd", size = 244005, upload-time = "2025-12-12T08:01:40.209Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aws-durable-execution-sdk-python"
|
||||
version = "1.1.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "boto3" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/63/9d/f3646d325d6c5ce3ad143d6e916d046ea94685c17ec6991331f6a233e187/aws_durable_execution_sdk_python-1.1.1.tar.gz", hash = "sha256:3812b60a72ab5c5fd9c1c1ffeca96260a9a79910b2c1fe4cb47c758b7768b1ce", size = 266978, upload-time = "2026-01-12T23:32:16.828Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/cf/98/c7ff676db3306ac59733d971167c69a9d86fef0fa410eafde270b2f80380/aws_durable_execution_sdk_python-1.1.1-py3-none-any.whl", hash = "sha256:d724cb5e59ba1dbfce9228b527daac88a24001bc00bac9e3adb6f5b79a283f11", size = 89799, upload-time = "2026-01-12T23:32:15.057Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aws-encryption-sdk"
|
||||
version = "4.0.3"
|
||||
@@ -746,11 +758,12 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "layercake"
|
||||
version = "0.12.0"
|
||||
version = "0.13.1"
|
||||
source = { directory = "../layercake" }
|
||||
dependencies = [
|
||||
{ name = "arnparse" },
|
||||
{ name = "authlib" },
|
||||
{ name = "aws-durable-execution-sdk-python" },
|
||||
{ name = "aws-lambda-powertools", extra = ["all"] },
|
||||
{ name = "cloudflare" },
|
||||
{ name = "dictdiffer" },
|
||||
@@ -763,6 +776,7 @@ dependencies = [
|
||||
{ name = "psycopg", extra = ["binary"] },
|
||||
{ name = "pycpfcnpj" },
|
||||
{ name = "pydantic", extra = ["email"] },
|
||||
{ name = "pydantic-core" },
|
||||
{ name = "pydantic-extra-types" },
|
||||
{ name = "python-calamine" },
|
||||
{ name = "python-multipart" },
|
||||
@@ -777,6 +791,7 @@ dependencies = [
|
||||
requires-dist = [
|
||||
{ name = "arnparse", specifier = ">=0.0.2" },
|
||||
{ name = "authlib", specifier = ">=1.6.5" },
|
||||
{ name = "aws-durable-execution-sdk-python", specifier = ">=1.1.1" },
|
||||
{ name = "aws-lambda-powertools", extras = ["all"], specifier = ">=3.23.0" },
|
||||
{ name = "cloudflare", specifier = ">=4.3.1" },
|
||||
{ name = "dictdiffer", specifier = ">=0.9.0" },
|
||||
@@ -789,6 +804,7 @@ requires-dist = [
|
||||
{ name = "psycopg", extras = ["binary"], specifier = ">=3.2.9" },
|
||||
{ name = "pycpfcnpj", specifier = ">=1.8" },
|
||||
{ name = "pydantic", extras = ["email"], specifier = ">=2.10.6" },
|
||||
{ name = "pydantic-core", specifier = ">=2.41.5" },
|
||||
{ name = "pydantic-extra-types", specifier = ">=2.10.3" },
|
||||
{ name = "python-calamine", specifier = ">=0.5.4" },
|
||||
{ name = "python-multipart", specifier = ">=0.0.20" },
|
||||
|
||||
Reference in New Issue
Block a user