From 6fb00c24c1526c0403e36d7e034f616a43fdea9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Rafael=20Siqueira?= Date: Sun, 11 Jan 2026 19:38:15 -0300 Subject: [PATCH] fix interest --- api.saladeaula.digital/app/config.py | 2 + .../app/routes/orders/checkout.py | 46 +++++++++++++++---- .../tests/routes/orders/test_checkout.py | 2 +- api.saladeaula.digital/tests/seeds.jsonl | 2 + .../_.$orgid.enrollments.buy/payment.tsx | 8 ++-- 5 files changed, 46 insertions(+), 14 deletions(-) diff --git a/api.saladeaula.digital/app/config.py b/api.saladeaula.digital/app/config.py index bc68c30..d4b40b4 100644 --- a/api.saladeaula.digital/app/config.py +++ b/api.saladeaula.digital/app/config.py @@ -9,7 +9,9 @@ COURSE_TABLE: str = os.getenv('COURSE_TABLE') # type: ignore BUCKET_NAME: str = os.getenv('BUCKET_NAME') # type: ignore +DUE_DAYS = 3 DEDUP_WINDOW_OFFSET_DAYS = 90 + PAPERFORGE_API = 'https://paperforge.saladeaula.digital' INTERNAL_EMAIL_DOMAIN = 'users.noreply.saladeaula.digital' diff --git a/api.saladeaula.digital/app/routes/orders/checkout.py b/api.saladeaula.digital/app/routes/orders/checkout.py index a3c66eb..e5393be 100644 --- a/api.saladeaula.digital/app/routes/orders/checkout.py +++ b/api.saladeaula.digital/app/routes/orders/checkout.py @@ -12,7 +12,7 @@ from aws_lambda_powertools.event_handler.exceptions import ( NotFoundError, ) from layercake.dateutils import now, ttl -from layercake.dynamodb import DynamoDBPersistenceLayer, KeyPair +from layercake.dynamodb import DynamoDBPersistenceLayer, KeyPair, SortKey from layercake.extra_types import CnpjStr, CpfStr, CreditCard, NameStr from pydantic import ( UUID4, @@ -26,7 +26,7 @@ from pydantic import ( from api_gateway import JSONResponse from boto3clients import dynamodb_client -from config import ORDER_TABLE +from config import DUE_DAYS, ORDER_TABLE from routes.enrollments.enroll import Enrollment router = Router() @@ -135,24 +135,29 @@ class Checkout(BaseModel): def checkout(payload: Checkout): now_ = now() order_id = payload.id + org_id = payload.org_id address = payload.address credit_card = payload.credit_card items = payload.items enrollments = payload.enrollments coupon = payload.coupon - subtotal = _sum_items(items) payment_method = payload.payment_method + installments = payload.installments + subtotal = _sum_items(items) due_date = ( - _calc_due_date(now_, 3) + _calc_due_date(now_, _get_due_days(org_id) if org_id else DUE_DAYS) if payment_method == 'BANK_SLIP' else now_ + timedelta(hours=1) ) discount = ( - _apply_discount(subtotal, coupon.amount, coupon.type) * -1 - if coupon - else Decimal('0') + _apply_discount(subtotal, coupon.amount, coupon.type) * -1 if coupon else 0 + ) + total = subtotal + discount if subtotal > 0 else 0 + interest_amount = ( + _calc_interest(total, installments) - total + if payment_method == 'CREDIT_CARD' and installments + else 0 ) - total = subtotal + discount if subtotal > Decimal('0') else Decimal('0') with dyn.transact_writer() as transact: transact.put( @@ -161,14 +166,21 @@ def checkout(payload: Checkout): 'sk': '0', 'status': 'PENDING', 'subtotal': subtotal, - 'total': total, + 'total': total + interest_amount, 'discount': discount, 'due_date': due_date, # Post-migration (orders): rename `create_date` to `created_at` 'create_date': now_, } | ({'coupon': coupon.code} if coupon else {}) - | ({'installments': payload.installments} if payload.installments else {}) + | ( + { + 'installments': payload.installments, + 'interest_amount': interest_amount, + } + if payload.installments + else {} + ) | payload.model_dump() ) @@ -293,3 +305,17 @@ def _calc_due_date( business_days -= 1 return current_dt + + +def _get_due_days( + org_id: str | UUID4, + default: int = DUE_DAYS, +) -> int: + return dyn.collection.get_item( + KeyPair( + pk=str(org_id), + sk=SortKey('METADATA#PAYMENT_POLICY', path_spec='due_days'), + ), + raise_on_error=False, + default=default, + ) diff --git a/api.saladeaula.digital/tests/routes/orders/test_checkout.py b/api.saladeaula.digital/tests/routes/orders/test_checkout.py index 888d494..ac9cdb8 100644 --- a/api.saladeaula.digital/tests/routes/orders/test_checkout.py +++ b/api.saladeaula.digital/tests/routes/orders/test_checkout.py @@ -27,7 +27,7 @@ def test_checkout_coupon( 'name': 'Branco do Brasil', 'email': 'bb@users.noreply.saladeaula.digital', 'payment_method': 'CREDIT_CARD', - 'installments': 12, + # 'installments': 2, 'credit_card': { 'holder_name': 'Sergio R Siqueira', 'number': '4111111111111111', diff --git a/api.saladeaula.digital/tests/seeds.jsonl b/api.saladeaula.digital/tests/seeds.jsonl index 29327e1..8d6d9e1 100644 --- a/api.saladeaula.digital/tests/seeds.jsonl +++ b/api.saladeaula.digital/tests/seeds.jsonl @@ -18,7 +18,9 @@ // Orgs {"id": "2a8963fc-4694-4fe2-953a-316d1b10f1f5", "sk": "0", "name": "pytest", "cnpj": "04978826000180"} {"id": "2a8963fc-4694-4fe2-953a-316d1b10f1f5", "sk": "METADATA#SUBSCRIPTION", "billing_day": 6} +{"id": "2a8963fc-4694-4fe2-953a-316d1b10f1f5", "sk": "METADATA#PAYMENT_POLICY", "due_days": 30, "created_at": "2025-07-15T15:04:36.369323-03:00"} {"id": "f6000f79-6e5c-49a0-952f-3bda330ef278", "sk": "0", "name": "Banco do Brasil", "cnpj": "00000000000191"} + // Org admins {"id": "f6000f79-6e5c-49a0-952f-3bda330ef278", "sk": "admins#15bacf02-1535-4bee-9022-19d106fd7518", "name": "Chester Bennington", "email": "chester@linkinpark.com"} diff --git a/apps/admin.saladeaula.digital/app/routes/_.$orgid.enrollments.buy/payment.tsx b/apps/admin.saladeaula.digital/app/routes/_.$orgid.enrollments.buy/payment.tsx index c1ce7ae..51585e1 100644 --- a/apps/admin.saladeaula.digital/app/routes/_.$orgid.enrollments.buy/payment.tsx +++ b/apps/admin.saladeaula.digital/app/routes/_.$orgid.enrollments.buy/payment.tsx @@ -85,7 +85,7 @@ export type CreditCard = z.infer export function Payment({}) { const wizard = useWizard() const { update, summary, ...state } = useWizardStore() - const { total } = summary() + const { subtotal, discount } = summary() const { control, handleSubmit } = useForm({ defaultValues: { payment_method: state.payment_method, @@ -156,7 +156,7 @@ export function Payment({}) { /> {paymentMethod === 'CREDIT_CARD' ? ( - + ) : null} @@ -367,7 +367,9 @@ export function CreditCard({ } const value = - calcInterest(total, installment) / installment + installment > 1 + ? calcInterest(total, installment) / installment + : total return (