add billing period

This commit is contained in:
2025-08-21 13:32:44 -03:00
parent 6c301d320b
commit c70a74b94a
14 changed files with 282 additions and 98 deletions

View File

@@ -112,31 +112,46 @@ def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool:
),
flatten_top=False,
)
order_layer.put_item(
item={
'id': pk,
'sk': f'{sk}#ENROLLMENT#{enrollment["id"]}',
'user': pick(('id', 'name'), enrollment['user']),
'course': pick(('id', 'name'), enrollment['course']),
'unit_price': course['unit_price'],
# Post-migration: uncomment the following line
# 'enrolled_at': enrollment['created_at'],
'enrolled_at': enrollment['create_date'],
'created_at': now_,
}
# Add author if present
| (
{
'author': {
'id': author['user_id'],
'name': author['name'],
}
with order_layer.transact_writer() as transact:
transact.put(
item={
'id': pk,
'sk': f'{sk}#ENROLLMENT#{enrollment["id"]}',
'user': pick(('id', 'name'), enrollment['user']),
'course': pick(('id', 'name'), enrollment['course']),
'unit_price': course['unit_price'],
# Post-migration: uncomment the following line
# 'enrolled_at': enrollment['created_at'],
'enrolled_at': enrollment['create_date'],
'created_at': now_,
}
if author
else {}
),
cond_expr='attribute_not_exists(sk)',
)
# Add author if present
| (
{
'author': {
'id': author['user_id'],
'name': author['name'],
}
}
if author
else {}
),
cond_expr='attribute_not_exists(sk)',
)
transact.update(
key=KeyPair(
pk=new_image['id'],
sk=new_image['sk'],
),
table_name=ENROLLMENT_TABLE,
update_expr='SET billing_period = :billing_period, \
updated_at = :updated_at',
expr_attr_values={
':billing_period': sk,
':updated_at': now_,
},
cond_expr='attribute_exists(sk)',
)
except Exception as exc:
logger.exception(
exc,

View File

@@ -38,7 +38,7 @@ def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool:
new_image = event.detail['new_image']
# Key pattern `BILLING#ORG#{org_id}`
*_, org_id = new_image['id'].split('#')
# Key pattern `START#{start_date}#END#{end_date}#SCHEDULE#AUTO_CLOSE`
# Key pattern `START#{start_date}#END#{end_date}
_, start_date, _, end_date, *_ = new_image['sk'].split('#')
emailmsg = Message(

View File

@@ -23,13 +23,15 @@ def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool:
new_image = event.detail['new_image']
order_id = new_image['id']
org_id = new_image['tenant_id']
# Post-migration: Uncomment the following line
# org_id = new_image['org_id']
result = enrollment_layer.collection.query(
KeyPair(
# Post-migration: Uncomment the following line
# f'SLOT#ORG#{org_id}',
f'vacancies#{org_id}',
order_id,
pk=f'vacancies#{org_id}',
sk=order_id,
),
limit=100,
)

View File

@@ -46,7 +46,7 @@ Resources:
Properties:
RetentionInDays: 90
EventBillingAddEnrollmentFunction:
EventBillingAppendEnrollmentFunction:
Type: AWS::Serverless::Function
Properties:
Handler: events.billing.append_enrollment.lambda_handler
@@ -55,7 +55,7 @@ Resources:
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref OrderTable
- DynamoDBReadPolicy:
- DynamoDBCrudPolicy:
TableName: !Ref EnrollmentTable
- DynamoDBReadPolicy:
TableName: !Ref CourseTable
@@ -69,6 +69,8 @@ Resources:
detail:
new_image:
sk: ["METADATA#SUBSCRIPTION_COVERED"]
billing_period:
- exists: false
EventBillingCancelEnrollmentFunction:
Type: AWS::Serverless::Function
@@ -91,10 +93,10 @@ Resources:
detail:
new_image:
sk: ["0"]
status: ["CANCELED"]
status: [CANCELED]
subscription_covered: [true]
old_image:
status: ["PENDING"]
status: [PENDING]
EventBillingCloseWindowFunction:
Type: AWS::Serverless::Function
@@ -117,6 +119,8 @@ Resources:
detail-type: [EXPIRE]
detail:
keys:
id:
- prefix: BILLING
sk:
- suffix: SCHEDULE#AUTO_CLOSE
@@ -149,9 +153,11 @@ Resources:
detail-type: [MODIFY]
detail:
new_image:
status: [CLOSED]
id:
- prefix: BILLING
s3_uri:
- exists: true
status: [CLOSED]
old_image:
status: [PENDING]

View File

@@ -9,10 +9,11 @@ def test_append_enrollment(
dynamodb_persistence_layer: DynamoDBPersistenceLayer,
lambda_context: LambdaContext,
):
enrollment_id = '945e8672-1d72-45c6-b76c-ac06aa8b52ab'
event = {
'detail': {
'new_image': {
'id': '945e8672-1d72-45c6-b76c-ac06aa8b52ab',
'id': enrollment_id,
'sk': 'METADATA#SUBSCRIPTION_COVERED',
'billing_day': 6,
'created_at': '2025-07-23T18:09:22.785678-03:00',
@@ -34,3 +35,9 @@ def test_append_enrollment(
== 'START#2025-05-06#END#2025-06-05#ENROLLMENT#945e8672-1d72-45c6-b76c-ac06aa8b52ab'
)
assert items[2]['sk'] == 'START#2025-05-06#END#2025-06-05'
print(
dynamodb_persistence_layer.collection.get_item(
KeyPair(enrollment_id, 'METADATA#SUBSCRIPTION_COVERED')
)
)

View File

@@ -24,6 +24,7 @@
// Enrollments
{"id": "945e8672-1d72-45c6-b76c-ac06aa8b52ab", "sk": "0", "course": {"id": "123", "name": "pytest"}, "user": {"id": "5OxmMjL-ujoR5IMGegQz", "name": "Sérgio R Siqueira"}, "create_date": "2025-06-05T12:13:54.371416+00:00"}
{"id": "945e8672-1d72-45c6-b76c-ac06aa8b52ab", "sk": "author", "name": "Carolina Brand", "user_id": "SMEXYk5MQkKCzknJpxqr8n"}
{"id": "945e8672-1d72-45c6-b76c-ac06aa8b52ab", "sk": "METADATA#SUBSCRIPTION_COVERED", "billing_day": 6, "org_id": "cJtK9SsnJhKPyxESe7g3DG", "created_at": "2025-07-23T18:09:22.785678-03:00"}
{"id": "77055ad7-03e1-4b07-98dc-a2f1a90913ba", "sk": "0", "course": {"id": "123", "name": "pytest"}, "user": {"id": "5OxmMjL-ujoR5IMGegQz", "name": "Sérgio R Siqueira"}, "create_date": "2025-06-05T12:13:54.371416+00:00"}
{"id": "77055ad7-03e1-4b07-98dc-a2f1a90913ba", "sk": "METADATA#SUBSCRIPTION_COVERED", "billing_day": 6, "org_id": "cJtK9SsnJhKPyxESe7g3DG"}