close bolling
This commit is contained in:
@@ -22,6 +22,7 @@ enrollment_layer = DynamoDBPersistenceLayer(ENROLLMENT_TABLE, dynamodb_client)
|
|||||||
@logger.inject_lambda_context
|
@logger.inject_lambda_context
|
||||||
def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool:
|
def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool:
|
||||||
new_image = event.detail['new_image']
|
new_image = event.detail['new_image']
|
||||||
|
now_ = now()
|
||||||
data = user_layer.get_item(
|
data = user_layer.get_item(
|
||||||
# Post-migration: uncomment the following line
|
# Post-migration: uncomment the following line
|
||||||
# KeyPair(new_image['org_id'], 'METADATA#BILLING_TERMS'),
|
# KeyPair(new_image['org_id'], 'METADATA#BILLING_TERMS'),
|
||||||
@@ -32,16 +33,27 @@ def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
enrollment_layer.put_item(
|
with enrollment_layer.transact_writer() as transact:
|
||||||
item={
|
transact.update(
|
||||||
'id': new_image['id'],
|
key=KeyPair(new_image['id'], '0'),
|
||||||
'sk': 'METADATA#BILLING_TERMS',
|
update_expr='SET subscription_covered = :subscription_covered, \
|
||||||
'org_id': new_image['tenant_id'],
|
updated_at = :updated_at',
|
||||||
'billing_day': data['billing_day'],
|
expr_attr_values={
|
||||||
'created_at': now(),
|
':subscription_covered': True,
|
||||||
},
|
':updated_at': now_,
|
||||||
cond_expr='attribute_not_exists(sk)',
|
},
|
||||||
)
|
cond_expr='attribute_exists(sk)',
|
||||||
|
)
|
||||||
|
transact.put(
|
||||||
|
item={
|
||||||
|
'id': new_image['id'],
|
||||||
|
'sk': 'METADATA#SUBSCRIPTION_COVERED',
|
||||||
|
'org_id': new_image['tenant_id'],
|
||||||
|
'billing_day': data['billing_day'],
|
||||||
|
'created_at': now(),
|
||||||
|
},
|
||||||
|
cond_expr='attribute_not_exists(sk)',
|
||||||
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
@@ -42,10 +42,10 @@ Resources:
|
|||||||
Properties:
|
Properties:
|
||||||
RetentionInDays: 90
|
RetentionInDays: 90
|
||||||
|
|
||||||
EventSetTermsIfSubscribedFunction:
|
EventSetSubscriptionCoveredFunction:
|
||||||
Type: AWS::Serverless::Function
|
Type: AWS::Serverless::Function
|
||||||
Properties:
|
Properties:
|
||||||
Handler: events.stopgap.set_terms_if_subscribed.lambda_handler
|
Handler: events.stopgap.set_subscription_covered.lambda_handler
|
||||||
LoggingConfig:
|
LoggingConfig:
|
||||||
LogGroup: !Ref EventLog
|
LogGroup: !Ref EventLog
|
||||||
Policies:
|
Policies:
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from aws_lambda_powertools.utilities.data_classes import (
|
|||||||
event_source,
|
event_source,
|
||||||
)
|
)
|
||||||
from aws_lambda_powertools.utilities.typing import LambdaContext
|
from aws_lambda_powertools.utilities.typing import LambdaContext
|
||||||
from layercake.dateutils import now, ttl
|
from layercake.dateutils import fromisoformat, now, ttl
|
||||||
from layercake.dynamodb import (
|
from layercake.dynamodb import (
|
||||||
DynamoDBPersistenceLayer,
|
DynamoDBPersistenceLayer,
|
||||||
KeyPair,
|
KeyPair,
|
||||||
@@ -35,12 +35,17 @@ def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool:
|
|||||||
data = enrollment_layer.collection.get_items(
|
data = enrollment_layer.collection.get_items(
|
||||||
TransactKey(enrollment_id) + SortKey('0') + SortKey('author')
|
TransactKey(enrollment_id) + SortKey('0') + SortKey('author')
|
||||||
)
|
)
|
||||||
|
created_at: datetime = fromisoformat(data['create_date']) # type: ignore
|
||||||
|
|
||||||
if not data:
|
if not data:
|
||||||
logger.debug('Enrollment not found')
|
logger.debug('Enrollment not found')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
start_date, end_date = get_billing_period(new_image['billing_day'])
|
start_date, end_date = get_billing_period(
|
||||||
|
new_image['billing_day'],
|
||||||
|
year=created_at.year,
|
||||||
|
month=created_at.month,
|
||||||
|
)
|
||||||
pk = 'BILLING#ORG#{org_id}'.format(org_id=org_id)
|
pk = 'BILLING#ORG#{org_id}'.format(org_id=org_id)
|
||||||
sk = 'START#{start}#END#{end}'.format(
|
sk = 'START#{start}#END#{end}'.format(
|
||||||
start=start_date.isoformat(),
|
start=start_date.isoformat(),
|
||||||
|
|||||||
68
order-events/app/events/billing/close_window.py
Normal file
68
order-events/app/events/billing/close_window.py
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import locale
|
||||||
|
import os
|
||||||
|
from datetime import date
|
||||||
|
|
||||||
|
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 jinja2 import Environment, FileSystemLoader
|
||||||
|
from layercake.dateutils import fromisoformat
|
||||||
|
from layercake.dynamodb import DynamoDBPersistenceLayer, KeyPair
|
||||||
|
from weasyprint import HTML
|
||||||
|
|
||||||
|
from boto3clients import dynamodb_client
|
||||||
|
from config import ORDER_TABLE
|
||||||
|
|
||||||
|
logger = Logger(__name__)
|
||||||
|
order_layer = DynamoDBPersistenceLayer(ORDER_TABLE, dynamodb_client)
|
||||||
|
curdir = os.path.dirname(__file__)
|
||||||
|
env = Environment(loader=FileSystemLoader(curdir))
|
||||||
|
locale.setlocale(locale.LC_ALL, 'pt_BR.UTF-8')
|
||||||
|
|
||||||
|
|
||||||
|
def currency(value: float | int) -> str:
|
||||||
|
return locale.currency(value, grouping=True)
|
||||||
|
|
||||||
|
|
||||||
|
def datetime_format(dt: date, fmt='%H:%M %d-%m-%y'):
|
||||||
|
if isinstance(dt, str):
|
||||||
|
dt = fromisoformat(dt) # type: ignore
|
||||||
|
|
||||||
|
return dt.strftime(fmt)
|
||||||
|
|
||||||
|
|
||||||
|
env.filters['datetime_format'] = datetime_format
|
||||||
|
env.filters['currency'] = currency
|
||||||
|
|
||||||
|
|
||||||
|
@event_source(data_class=EventBridgeEvent)
|
||||||
|
@logger.inject_lambda_context
|
||||||
|
def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool:
|
||||||
|
new_image = event.detail['new_image']
|
||||||
|
_, start_date, _, end_date, *_ = new_image['sk'].split('#')
|
||||||
|
|
||||||
|
result = order_layer.collection.query(
|
||||||
|
KeyPair(
|
||||||
|
pk=new_image['id'],
|
||||||
|
sk=f'START#{start_date}#END#{end_date}#ENROLLMENT',
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
template = env.get_template('tmpl.html')
|
||||||
|
html_rendered = template.render(
|
||||||
|
start_date=start_date,
|
||||||
|
end_date=end_date,
|
||||||
|
items=result['items'],
|
||||||
|
)
|
||||||
|
|
||||||
|
HTML(string=html_rendered, base_url='').write_pdf('cert.pdf')
|
||||||
|
|
||||||
|
return order_layer.update_item(
|
||||||
|
key=KeyPair(new_image['id'], new_image['sk']),
|
||||||
|
update_expr='SET #status = :status',
|
||||||
|
expr_attr_names={'#status': 'status'},
|
||||||
|
expr_attr_values={':status': 'CLOSED'},
|
||||||
|
)
|
||||||
BIN
order-events/app/events/billing/fonts/SF-Pro.ttf
Executable file
BIN
order-events/app/events/billing/fonts/SF-Pro.ttf
Executable file
Binary file not shown.
200
order-events/app/events/billing/tmpl.html
Normal file
200
order-events/app/events/billing/tmpl.html
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title></title>
|
||||||
|
<meta name="author" content="EDUSEG® <https://eduseg.com.br>" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<style>
|
||||||
|
@page {
|
||||||
|
size: A4 portrait;
|
||||||
|
margin: 0.458cm;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "SF-Pro";
|
||||||
|
src: url("fonts/SF-Pro.ttf") format("truetype");
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body,
|
||||||
|
div,
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
ul,
|
||||||
|
p,
|
||||||
|
a {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
font: inherit;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-family: SF-Pro;
|
||||||
|
font-size: 11pt;
|
||||||
|
line-height: 1.4;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
width: 100%;
|
||||||
|
break-after: page;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
table-layout: auto;
|
||||||
|
width: 100%;
|
||||||
|
border-spacing: 0;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
border: 1px solid #efefef;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding: 0.625rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody > tr > td {
|
||||||
|
border-top: 1px solid #efefef;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead {
|
||||||
|
background-color: #f3f4f680;
|
||||||
|
font-weight: 600;
|
||||||
|
display: table-header-group;
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
page-break-inside: avoid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.space-y-0\.5 > :not(:last-child) {
|
||||||
|
margin-bottom: 0.125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.space-y-2\.5 > :not(:last-child) {
|
||||||
|
margin-bottom: 0.625rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<section class="space-y-2.5">
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 1143.4 257.88"
|
||||||
|
style="width: 10rem"
|
||||||
|
>
|
||||||
|
<defs>
|
||||||
|
<style>
|
||||||
|
.cls-1 {
|
||||||
|
fill: #8cd366;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cls-2 {
|
||||||
|
fill: #2e3524;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path
|
||||||
|
class="cls-1"
|
||||||
|
d="M119.06,170.25l-53.68-24.18c-1.47-.94-3.35-.94-4.82,0l-53.68,24.18c-2.98,1.9-6.89-.24-6.89-3.77V7.01C0,4.54,2.01,2.54,4.48,2.54h117c2.47,0,4.48,2.01,4.48,4.48v159.46c0,3.54-3.91,5.68-6.89,3.77Z"
|
||||||
|
/>
|
||||||
|
<g>
|
||||||
|
<path
|
||||||
|
class="cls-2"
|
||||||
|
d="M73.52,57.89H20.82v15.77h52.7v-15.77Z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="cls-2"
|
||||||
|
d="M84.06,86.96H20.82v20.97h63.24v-20.97Z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="cls-2"
|
||||||
|
d="M84.06,23.67H20.82v20.97h63.24v-20.97Z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="cls-2"
|
||||||
|
d="M105.14,102.66c0-2.91-2.36-5.27-5.27-5.27s-5.27,2.36-5.27,5.27,2.36,5.27,5.27,5.27,5.27-2.36,5.27-5.27Z"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path
|
||||||
|
class="cls-2"
|
||||||
|
d="M191.46,2.54h72.24v34.76h-34.54v69.52h30.81v31h-30.81v82.76h34.54v34.76h-72.24V2.54Z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="cls-2"
|
||||||
|
d="M283.8,2.54h45.22c8.38,0,16.01,1.84,22.92,5.52,6.91,3.68,12.35,8.75,16.33,15.17,3.98,6.42,5.97,13.65,5.97,21.65v168.12c0,8-1.94,15.23-5.8,21.65-3.88,6.42-9.26,11.49-16.18,15.17-6.91,3.68-14.65,5.54-23.23,5.54h-45.22V2.54ZM334.52,222.11c1.36-1.46,2.03-3.27,2.03-5.37V41.12c-.2-2.1-1.04-3.89-2.52-5.37-1.47-1.46-3.25-2.22-5.34-2.22h-10.96v190.79h11.27c2.29,0,4.12-.73,5.49-2.22h.02Z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="cls-2"
|
||||||
|
d="M415.84,252.32c-6.81-3.68-12.2-8.73-16.18-15.17-3.97-6.42-5.97-13.63-5.97-21.65V2.54h37.68v218.61c0,2.1.73,3.91,2.2,5.37,1.46,1.48,3.25,2.22,5.34,2.22,2.29,0,4.12-.73,5.49-2.22,1.36-1.46,2.03-3.27,2.03-5.37V2.54h37.68v212.98c0,8.02-1.94,15.23-5.8,21.65-3.88,6.42-9.26,11.49-16.18,15.17-6.92,3.68-14.65,5.54-23.23,5.54s-16.27-1.84-23.08-5.54l.04-.02Z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="cls-2"
|
||||||
|
d="M526.39,252.32c-6.81-3.68-12.2-8.73-16.18-15.17-3.97-6.42-5.97-13.63-5.97-21.65v-61.61h37.68v67.24c0,2.1.73,3.91,2.2,5.37,1.45,1.48,3.25,2.21,5.34,2.21,2.29,0,4.12-.73,5.49-2.21,1.36-1.47,2.03-3.27,2.03-5.37v-60.94c0-4.43-1.73-8.06-5.19-10.91-3.45-2.84-9.05-6.27-16.8-10.27-6.49-3.36-11.78-6.37-15.86-9.01-4.09-2.63-7.6-6.16-10.52-10.59-2.93-4.43-4.4-9.58-4.4-15.49v-61.57c0-8,1.98-15.21,5.97-21.65,3.98-6.42,9.37-11.47,16.18-15.17,6.79-3.68,14.5-5.52,23.08-5.52s16.33,1.84,23.23,5.52c6.91,3.68,12.3,8.75,16.18,15.17,3.88,6.42,5.8,13.65,5.8,21.65v55.62h-37.68v-61.25c0-2.1-.69-3.89-2.03-5.37-1.36-1.46-3.19-2.22-5.49-2.22-2.09,0-3.88.73-5.34,2.22-1.48,1.48-2.2,3.27-2.2,5.37v54.61c0,4.84,1.83,8.81,5.51,11.85,3.66,3.06,9.57,6.91,17.75,11.53,6.29,3.38,11.4,6.33,15.4,8.84,3.97,2.53,7.33,5.84,10.04,9.95,2.72,4.11,4.09,8.81,4.09,14.06v67.94c0,8.02-1.94,15.23-5.8,21.65-3.88,6.42-9.26,11.49-16.18,15.17-6.92,3.68-14.65,5.54-23.23,5.54s-16.27-1.84-23.08-5.54Z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="cls-2"
|
||||||
|
d="M613.84,2.54h72.24v34.76h-34.54v69.52h30.81v31h-30.81v82.76h34.54v34.76h-72.24V2.54Z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="cls-2"
|
||||||
|
d="M720.31,252.32c-4.4-3.27-7.91-7.9-10.52-13.9-2.61-6.01-3.92-12.9-3.92-20.69V42.03c0-7.79,1.98-14.91,5.97-21.33,3.98-6.42,9.43-11.47,16.33-15.17,6.91-3.68,14.56-5.52,22.94-5.52s16.07,1.84,23.08,5.52c7.02,3.68,12.45,8.75,16.33,15.17,3.88,6.42,5.8,13.54,5.8,21.33v73.95h-37.68V36.71c0-2.1-.69-3.89-2.03-5.37-1.36-1.46-3.19-2.22-5.49-2.22-2.09,0-3.88.73-5.34,2.22-1.48,1.48-2.2,3.27-2.2,5.37v181.02c0,2.1.73,3.91,2.2,5.37,1.45,1.48,3.25,2.22,5.34,2.22,2.3,0,4.13-.73,5.49-2.22,1.36-1.47,2.03-3.27,2.03-5.37v-36.02h-9.11v-40.13h46.78v113.76h-37.68v-11.06c-2.31,4.23-5.34,7.42-9.11,9.63-3.77,2.22-8.47,3.32-14.13,3.32s-10.67-1.63-15.08-4.9l-.02-.02Z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="cls-2"
|
||||||
|
d="M824.08,19.6h-4.8l-.04-2.89h4.29c.65-.01,1.26-.12,1.82-.31.56-.21,1.01-.5,1.36-.89.34-.4.51-.89.51-1.47,0-.73-.13-1.3-.38-1.73-.24-.43-.65-.73-1.24-.91-.58-.19-1.36-.29-2.35-.29h-2.96v15.98h-3.22V8.24h6.18c1.47,0,2.73.21,3.8.64,1.08.41,1.91,1.05,2.49,1.91.59.84.89,1.9.89,3.18,0,.8-.19,1.51-.56,2.13-.37.62-.92,1.16-1.64,1.62-.71.44-1.59.81-2.62,1.09-.04,0-.1.05-.16.16-.04.1-.09.16-.13.16-.25.15-.42.26-.49.33-.06.06-.13.1-.2.11-.06.01-.24.02-.53.02ZM823.86,19.6l.47-2.2c2.31,0,3.89.5,4.73,1.51.85.99,1.27,2.26,1.27,3.8v1.2c0,.55.02,1.07.07,1.58.06.49.16.9.31,1.24v.36h-3.31c-.15-.39-.24-.93-.27-1.64-.02-.71-.02-1.23-.02-1.56v-1.16c0-1.08-.24-1.87-.73-2.38-.49-.5-1.33-.76-2.51-.76ZM810.38,17.93c0,1.97.33,3.81,1,5.51.68,1.69,1.63,3.17,2.84,4.44,1.22,1.26,2.61,2.24,4.2,2.96,1.6.7,3.3,1.04,5.11,1.04s3.53-.35,5.11-1.04c1.59-.71,2.98-1.7,4.18-2.96,1.2-1.27,2.14-2.76,2.82-4.44.68-1.7,1.02-3.54,1.02-5.51s-.34-3.8-1.02-5.49c-.68-1.69-1.62-3.16-2.82-4.42-1.2-1.26-2.59-2.24-4.18-2.93-1.59-.71-3.29-1.07-5.11-1.07s-3.51.36-5.11,1.07c-1.59.7-2.98,1.67-4.2,2.93-1.22,1.26-2.16,2.73-2.84,4.42-.67,1.69-1,3.52-1,5.49ZM807.75,17.93c0-2.36.41-4.54,1.22-6.55.81-2.01,1.95-3.77,3.4-5.27,1.45-1.51,3.13-2.68,5.02-3.51,1.91-.84,3.96-1.27,6.13-1.27s4.21.42,6.11,1.27c1.91.83,3.59,2,5.02,3.51,1.45,1.5,2.59,3.25,3.4,5.27.83,2.01,1.25,4.2,1.25,6.55s-.42,4.54-1.25,6.55c-.81,2.01-1.95,3.78-3.4,5.31-1.44,1.51-3.11,2.69-5.02,3.53-1.9.84-3.93,1.27-6.11,1.27s-4.22-.42-6.13-1.27c-1.9-.84-3.57-2.02-5.02-3.53-1.45-1.53-2.58-3.3-3.4-5.31-.82-2.01-1.22-4.2-1.22-6.55Z"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Matrículas realizadas entre
|
||||||
|
<strong>{{ start_date|datetime_format('%d/%m/%Y') }}</strong> e
|
||||||
|
<strong>{{ end_date|datetime_format('%d/%m/%Y') }}</strong>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<table class="table-layout border border-gray-300">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td>Curso</td>
|
||||||
|
<td>Colaborador</td>
|
||||||
|
<td>Matrículado em</td>
|
||||||
|
<td>Valor unit.</td>
|
||||||
|
<td>Autor</td>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for x in items %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ x.course.name }}</td>
|
||||||
|
<td>{{ x.user.name }}</td>
|
||||||
|
<td>
|
||||||
|
{{ x.enrolled_at|datetime_format('%d/%m/%Y, %H:%M')
|
||||||
|
}}
|
||||||
|
</td>
|
||||||
|
<td>{{ x.unit_price|currency }}</td>
|
||||||
|
<td>{{ x.author.name }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</section>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -64,7 +64,28 @@ Resources:
|
|||||||
detail-type: [INSERT]
|
detail-type: [INSERT]
|
||||||
detail:
|
detail:
|
||||||
new_image:
|
new_image:
|
||||||
sk: ["METADATA#BILLING_TERMS"]
|
sk: ["METADATA#SUBSCRIPTION_COVERED"]
|
||||||
|
|
||||||
|
EventBillingCloseWindowFunction:
|
||||||
|
Type: AWS::Serverless::Function
|
||||||
|
Properties:
|
||||||
|
Handler: events.billing.close_window.lambda_handler
|
||||||
|
LoggingConfig:
|
||||||
|
LogGroup: !Ref EventLog
|
||||||
|
Policies:
|
||||||
|
- DynamoDBCrudPolicy:
|
||||||
|
TableName: !Ref OrderTable
|
||||||
|
Events:
|
||||||
|
Event:
|
||||||
|
Type: EventBridgeRule
|
||||||
|
Properties:
|
||||||
|
Pattern:
|
||||||
|
resources: [!Ref OrderTable]
|
||||||
|
detail-type: [EXPIRE]
|
||||||
|
detail:
|
||||||
|
new_image:
|
||||||
|
sk:
|
||||||
|
- suffix: SCHEDULE#AUTO_CLOSE
|
||||||
|
|
||||||
EventAppendOrgIdFunction:
|
EventAppendOrgIdFunction:
|
||||||
Type: AWS::Serverless::Function
|
Type: AWS::Serverless::Function
|
||||||
@@ -128,7 +149,7 @@ Resources:
|
|||||||
Policies:
|
Policies:
|
||||||
- DynamoDBWritePolicy:
|
- DynamoDBWritePolicy:
|
||||||
TableName: !Ref OrderTable
|
TableName: !Ref OrderTable
|
||||||
- DynamoDBWritePolicy:
|
- DynamoDBCrudPolicy:
|
||||||
TableName: !Ref EnrollmentTable
|
TableName: !Ref EnrollmentTable
|
||||||
Events:
|
Events:
|
||||||
Event:
|
Event:
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
from aws_lambda_powertools.utilities.typing import LambdaContext
|
from aws_lambda_powertools.utilities.typing import LambdaContext
|
||||||
from layercake.dynamodb import DynamoDBPersistenceLayer, PartitionKey
|
from layercake.dynamodb import DynamoDBPersistenceLayer, PartitionKey
|
||||||
|
|
||||||
import events.reporting.add_item as app
|
import events.billing.append_enrollment as app
|
||||||
|
|
||||||
|
|
||||||
def test_add_item(
|
def test_append_enrollment(
|
||||||
dynamodb_seeds,
|
dynamodb_seeds,
|
||||||
dynamodb_persistence_layer: DynamoDBPersistenceLayer,
|
dynamodb_persistence_layer: DynamoDBPersistenceLayer,
|
||||||
lambda_context: LambdaContext,
|
lambda_context: LambdaContext,
|
||||||
@@ -13,7 +13,7 @@ def test_add_item(
|
|||||||
'detail': {
|
'detail': {
|
||||||
'new_image': {
|
'new_image': {
|
||||||
'id': '945e8672-1d72-45c6-b76c-ac06aa8b52ab',
|
'id': '945e8672-1d72-45c6-b76c-ac06aa8b52ab',
|
||||||
'sk': 'METADATA#BILLING_TERMS',
|
'sk': 'METADATA#SUBSCRIPTION_COVERED',
|
||||||
'billing_day': 5,
|
'billing_day': 5,
|
||||||
'created_at': '2025-07-23T18:09:22.785678-03:00',
|
'created_at': '2025-07-23T18:09:22.785678-03:00',
|
||||||
'org_id': 'edp8njvgQuzNkLx2ySNfAD',
|
'org_id': 'edp8njvgQuzNkLx2ySNfAD',
|
||||||
@@ -26,5 +26,11 @@ def test_add_item(
|
|||||||
r = dynamodb_persistence_layer.collection.query(
|
r = dynamodb_persistence_layer.collection.query(
|
||||||
PartitionKey('BILLING#ORG#edp8njvgQuzNkLx2ySNfAD')
|
PartitionKey('BILLING#ORG#edp8njvgQuzNkLx2ySNfAD')
|
||||||
)
|
)
|
||||||
|
items = r['items']
|
||||||
|
|
||||||
print(r)
|
assert items[0]['sk'] == 'START#2025-06-05#END#2025-07-04#SCHEDULE#AUTO_CLOSE'
|
||||||
|
assert (
|
||||||
|
items[1]['sk']
|
||||||
|
== 'START#2025-06-05#END#2025-07-04#ENROLLMENT#945e8672-1d72-45c6-b76c-ac06aa8b52ab'
|
||||||
|
)
|
||||||
|
assert items[2]['sk'] == 'START#2025-06-05#END#2025-07-04'
|
||||||
29
order-events/tests/events/billing/test_close_window.py
Normal file
29
order-events/tests/events/billing/test_close_window.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
from aws_lambda_powertools.utilities.typing import LambdaContext
|
||||||
|
from layercake.dynamodb import DynamoDBPersistenceLayer, PartitionKey
|
||||||
|
|
||||||
|
import events.billing.close_window as app
|
||||||
|
|
||||||
|
|
||||||
|
def test_append_enrollment(
|
||||||
|
dynamodb_seeds,
|
||||||
|
dynamodb_persistence_layer: DynamoDBPersistenceLayer,
|
||||||
|
lambda_context: LambdaContext,
|
||||||
|
):
|
||||||
|
event = {
|
||||||
|
'detail': {
|
||||||
|
'new_image': {
|
||||||
|
'id': 'BILLING#ORG#BES6dmWgTMXRYmfDyYYXUF',
|
||||||
|
'sk': 'START#2025-07-01#END#2025-07-31#SCHEDULE#AUTO_CLOSE',
|
||||||
|
'created_at': '2025-07-24T15:20:52.464244-03:00',
|
||||||
|
'ttl': 1754017200,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert app.lambda_handler(event, lambda_context) # type: ignore
|
||||||
|
|
||||||
|
# r = dynamodb_persistence_layer.collection.query(
|
||||||
|
# PartitionKey('BILLING#ORG#edp8njvgQuzNkLx2ySNfAD')
|
||||||
|
# )
|
||||||
|
|
||||||
|
# print(r)
|
||||||
@@ -15,3 +15,6 @@
|
|||||||
{"id": {"S": "945e8672-1d72-45c6-b76c-ac06aa8b52ab"}, "sk": {"S": "author"}, "name": {"S": "Carolina Brand"}, "user_id": {"S": "SMEXYk5MQkKCzknJpxqr8n"}}
|
{"id": {"S": "945e8672-1d72-45c6-b76c-ac06aa8b52ab"}, "sk": {"S": "author"}, "name": {"S": "Carolina Brand"}, "user_id": {"S": "SMEXYk5MQkKCzknJpxqr8n"}}
|
||||||
{"id": {"S": "CUSTOM_PRICING#ORG#edp8njvgQuzNkLx2ySNfAD"},"sk": {"S": "COURSE#123"},"created_at": {"S": "2025-07-24T16:10:09.304073-03:00"},"unit_price": {"N": "79.2"}}
|
{"id": {"S": "CUSTOM_PRICING#ORG#edp8njvgQuzNkLx2ySNfAD"},"sk": {"S": "COURSE#123"},"created_at": {"S": "2025-07-24T16:10:09.304073-03:00"},"unit_price": {"N": "79.2"}}
|
||||||
{"id": {"S": "123"},"sk": {"S": "0"},"access_period": {"N": "360"},"cert": {"M": {"exp_interval": {"N": "360"}}},"created_at": {"S": "2024-12-30T00:33:33.088916-03:00"},"metadata__konviva_class_id": {"N": "194"},"metadata__unit_price": {"N": "99"},"name": {"S": "Direção Defensiva (08 horas)"},"tenant_id": {"S": "*"},"updated_at": {"S": "2025-07-24T00:00:24.639003-03:00"}}
|
{"id": {"S": "123"},"sk": {"S": "0"},"access_period": {"N": "360"},"cert": {"M": {"exp_interval": {"N": "360"}}},"created_at": {"S": "2024-12-30T00:33:33.088916-03:00"},"metadata__konviva_class_id": {"N": "194"},"metadata__unit_price": {"N": "99"},"name": {"S": "Direção Defensiva (08 horas)"},"tenant_id": {"S": "*"},"updated_at": {"S": "2025-07-24T00:00:24.639003-03:00"}}
|
||||||
|
{"id": {"S": "BILLING#ORG#BES6dmWgTMXRYmfDyYYXUF"},"sk": {"S": "START#2025-07-01#END#2025-07-31"},"created_at": {"S": "2025-07-24T15:20:52.464244-03:00"},"status": {"S": "PENDING"}}
|
||||||
|
{"id": {"S": "BILLING#ORG#BES6dmWgTMXRYmfDyYYXUF"},"sk": {"S": "START#2025-07-01#END#2025-07-31#ENROLLMENT#a08c94a2-7ee4-45fd-bfe7-73568c738b8b"},"author": {"M": {"id": {"S": "SMEXYk5MQkKCzknJpxqr8n"},"name": {"S": "Carolina Brand"}}},"course": {"M": {"id": {"S": "7f7905aa-ec6d-4189-b884-50fa9b1bd0b8"},"name": {"S": "NR-10 Reciclagem: 08 horas"}}},"created_at": {"S": "2025-07-24T16:38:33.095216-03:00"},"enrolled_at": {"S": "2025-07-24T11:26:56.975207-03:00"},"unit_price": {"N": "169"},"user": {"M": {"id": {"S": "iPWidwn4HsYtikiZD33smV"},"name": {"S": "William da Silva Nascimento"}}}}
|
||||||
|
{"id": {"S": "BILLING#ORG#BES6dmWgTMXRYmfDyYYXUF"},"sk": {"S": "START#2025-07-01#END#2025-07-31#ENROLLMENT#ac09e8da-6cb2-4e31-84e7-238df2647a7a"},"author": {"M": {"id": {"S": "SMEXYk5MQkKCzknJpxqr8n"},"name": {"S": "Carolina Brand"}}},"course": {"M": {"id": {"S": "7f7905aa-ec6d-4189-b884-50fa9b1bd0b8"},"name": {"S": "NR-10 Reciclagem: 08 horas"}}},"created_at": {"S": "2025-07-24T16:38:58.694031-03:00"},"enrolled_at": {"S": "2025-07-24T11:26:56.913746-03:00"},"unit_price": {"N": "169"},"user": {"M": {"id": {"S": "ca8c9fca-b508-4842-8a48-fd5cc5632ac0"},"name": {"S": "Geovane Soares De Lima"}}}}
|
||||||
Reference in New Issue
Block a user