Skip to content

Commit 809a4d6

Browse files
authored
✨ Changes in auto-recharge limit policy (🗃️, ⚠️) (#4946)
1 parent da7ba29 commit 809a4d6

File tree

16 files changed

+173
-139
lines changed

16 files changed

+173
-139
lines changed

.env-devel

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,9 @@ LOG_FORMAT_LOCAL_DEV_ENABLED=1
6464
WEBSERVER_PAYMENTS={}
6565
PAYMENTS_ACCESS_TOKEN_EXPIRE_MINUTES=30
6666
PAYMENTS_ACCESS_TOKEN_SECRET_KEY=2c0411810565e063309be1457009fb39ce023946f6a354e6935107b57676
67-
PAYMENTS_AUTORECHARGE_DEFAULT_MIN_BALANCE=20.0
67+
PAYMENTS_AUTORECHARGE_DEFAULT_MONTHLY_LIMIT=10000
6868
PAYMENTS_AUTORECHARGE_DEFAULT_TOP_UP_AMOUNT=100.0
69+
PAYMENTS_AUTORECHARGE_MIN_BALANCE_IN_CREDITS=100
6970
PAYMENTS_FAKE_COMPLETION_DELAY_SEC=10
7071
PAYMENTS_FAKE_COMPLETION=0
7172
PAYMENTS_GATEWAY_API_SECRET=replace-with-api-secret

packages/models-library/src/models_library/api_schemas_webserver/wallets.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from decimal import Decimal
33
from typing import Any, ClassVar, Literal, TypeAlias
44

5-
from pydantic import Field, HttpUrl, PositiveInt
5+
from pydantic import Field, HttpUrl
66

77
from ..basic_types import IDStr, NonNegativeDecimal
88
from ..users import GroupID
@@ -171,23 +171,23 @@ class GetWalletAutoRecharge(OutputSchema):
171171
...,
172172
description="Payment method in the wallet used to perform the auto-recharge payments or None if still undefined",
173173
)
174-
min_balance_in_usd: NonNegativeDecimal = Field(
174+
min_balance_in_credits: NonNegativeDecimal = Field(
175175
...,
176-
description="Minimum balance in USD that triggers an auto-recharge",
176+
description="Minimum balance in credits that triggers an auto-recharge [Read only]",
177177
)
178178
top_up_amount_in_usd: NonNegativeDecimal = Field(
179179
...,
180180
description="Amount in USD payed when auto-recharge condition is satisfied",
181181
)
182-
top_up_countdown: PositiveInt | None = Field(
183-
default=None,
184-
description="Maximum number of top-ups left or None to denote unlimited",
182+
monthly_limit_in_usd: NonNegativeDecimal | None = Field(
183+
...,
184+
description="Maximum amount in USD charged within a natural month."
185+
"None indicates no limit.",
185186
)
186187

187188

188189
class ReplaceWalletAutoRecharge(InputSchema):
189190
enabled: bool
190191
payment_method_id: PaymentMethodID
191-
min_balance_in_usd: NonNegativeDecimal
192192
top_up_amount_in_usd: NonNegativeDecimal
193-
top_up_countdown: PositiveInt | None
193+
monthly_limit_in_usd: NonNegativeDecimal | None

packages/models-library/src/models_library/invitations.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from datetime import datetime
22

3-
from pydantic import BaseModel, Field, PositiveInt
3+
from pydantic import BaseModel, Field, PositiveInt, validator
44

55
from .emails import LowerCaseEmailStr
66

@@ -10,7 +10,7 @@ class InvitationInputs(BaseModel):
1010

1111
issuer: str = Field(
1212
...,
13-
description="Identifies who issued the invitation. E.g. an email, a service name etc",
13+
description="Identifies who issued the invitation. E.g. an email, a service name etc. NOTE: it will be trimmed if exceeds maximum",
1414
min_length=1,
1515
max_length=30,
1616
)
@@ -28,6 +28,13 @@ class InvitationInputs(BaseModel):
2828
description="If set, the account's primary wallet will add extra credits corresponding to this ammount in USD",
2929
)
3030

31+
@validator("issuer", pre=True)
32+
@classmethod
33+
def trim_long_issuers_to_max_length(cls, v):
34+
if v and isinstance(v, str):
35+
return v[:29]
36+
return v
37+
3138

3239
class InvitationContent(InvitationInputs):
3340
"""Data in an invitation"""

packages/postgres-database/VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.10.0
1+
0.11.0

packages/postgres-database/setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[bumpversion]
2-
current_version = 0.10.0
2+
current_version = 0.11.0
33
commit = True
44
message = packages/postgres-database version: {current_version} → {new_version}
55
tag = False
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"""rm cols in payments_autorecharge
2+
3+
Revision ID: d0d544695487
4+
Revises: 2a4b4167e088
5+
Create Date: 2023-10-27 18:29:46.409910+00:00
6+
7+
"""
8+
import sqlalchemy as sa
9+
from alembic import op
10+
11+
# revision identifiers, used by Alembic.
12+
revision = "d0d544695487"
13+
down_revision = "2a4b4167e088"
14+
branch_labels = None
15+
depends_on = None
16+
17+
18+
def upgrade():
19+
# ### commands auto generated by Alembic - please adjust! ###
20+
op.add_column(
21+
"payments_autorecharge",
22+
sa.Column("monthly_limit_in_usd", sa.Numeric(scale=2), nullable=True),
23+
)
24+
op.drop_column("payments_autorecharge", "top_up_countdown")
25+
op.drop_column("payments_autorecharge", "min_balance_in_usd")
26+
# ### end Alembic commands ###
27+
28+
29+
def downgrade():
30+
# ### commands auto generated by Alembic - please adjust! ###
31+
op.add_column(
32+
"payments_autorecharge",
33+
sa.Column(
34+
"min_balance_in_usd",
35+
sa.NUMERIC(),
36+
server_default=sa.text("0"),
37+
autoincrement=False,
38+
nullable=False,
39+
),
40+
)
41+
op.add_column(
42+
"payments_autorecharge",
43+
sa.Column("top_up_countdown", sa.INTEGER(), autoincrement=False, nullable=True),
44+
)
45+
op.drop_column("payments_autorecharge", "monthly_limit_in_usd")
46+
# ### end Alembic commands ###

packages/postgres-database/src/simcore_postgres_database/models/payments_autorecharge.py

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -60,37 +60,23 @@
6060
# delete the line which will result in wallet default introduced by the api-layer. The only dissadvantage is that
6161
# the user would loose his previous settings.
6262
),
63-
sa.Column(
64-
"min_balance_in_usd",
65-
sa.Numeric(**NUMERIC_KWARGS), # type: ignore
66-
nullable=False,
67-
server_default=sa.text("0"),
68-
doc="[Required] Minimum or equal balance in USD that triggers auto-recharge",
69-
),
7063
sa.Column(
7164
"top_up_amount_in_usd",
7265
sa.Numeric(**NUMERIC_KWARGS), # type: ignore
7366
nullable=False,
74-
doc="[Required] Increase in USD when balance reaches min_balance_in_usd",
67+
doc="[Required] Increase in USD when balance reaches minimum balance threshold",
7568
),
7669
sa.Column(
77-
"top_up_countdown",
78-
sa.Integer(),
70+
"monthly_limit_in_usd",
71+
sa.Numeric(**NUMERIC_KWARGS), # type: ignore
7972
nullable=True,
8073
server_default=None,
81-
doc="[Optional] Number of auto-recharges left."
82-
"If it reaches zero, then auto-recharge stops."
83-
"Used to limit the number of times that the system can auto-recharge."
84-
"If None, then inc has no limit.",
74+
doc="[Optional] Maximum amount in USD charged within a natural month"
75+
"If None, indicates no limit",
8576
),
8677
# time-stamps
8778
column_created_datetime(timezone=True),
8879
column_modified_datetime(timezone=True),
89-
#
90-
sa.CheckConstraint(
91-
"(top_up_countdown >= 0) OR (top_up_countdown IS NULL)",
92-
name="check_top_up_countdown_nonnegative",
93-
),
9480
)
9581

9682

packages/postgres-database/src/simcore_postgres_database/utils_payments_autorecharge.py

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,8 @@ def get_wallet_autorecharge(wallet_id) -> sa.sql.Select:
2626
payments_methods.c.wallet_id,
2727
payments_autorecharge.c.primary_payment_method_id,
2828
payments_autorecharge.c.enabled,
29-
payments_autorecharge.c.min_balance_in_usd,
3029
payments_autorecharge.c.top_up_amount_in_usd,
31-
payments_autorecharge.c.top_up_countdown,
30+
payments_autorecharge.c.monthly_limit_in_usd,
3231
)
3332
.select_from(
3433
payments_methods.join(
@@ -52,19 +51,17 @@ def upsert_wallet_autorecharge(
5251
wallet_id,
5352
enabled,
5453
primary_payment_method_id,
55-
min_balance_in_usd,
5654
top_up_amount_in_usd,
57-
top_up_countdown,
55+
monthly_limit_in_usd,
5856
):
5957
# using this primary payment-method, create an autorecharge
6058
# NOTE: requires the entire
6159
values = {
6260
"wallet_id": wallet_id,
6361
"enabled": enabled,
6462
"primary_payment_method_id": primary_payment_method_id,
65-
"min_balance_in_usd": min_balance_in_usd,
6663
"top_up_amount_in_usd": top_up_amount_in_usd,
67-
"top_up_countdown": top_up_countdown,
64+
"monthly_limit_in_usd": monthly_limit_in_usd,
6865
}
6966

7067
insert_stmt = pg_insert(payments_autorecharge).values(**values)
@@ -81,17 +78,3 @@ def update_wallet_autorecharge(wallet_id, **values) -> sa.sql.Update:
8178
.where(payments_autorecharge.c.wallet_id == wallet_id)
8279
.returning(payments_autorecharge.c.id)
8380
)
84-
85-
@staticmethod
86-
def decrease_wallet_autorecharge_countdown(wallet_id) -> sa.sql.Update:
87-
return (
88-
payments_autorecharge.update()
89-
.where(
90-
(payments_autorecharge.c.wallet_id == wallet_id)
91-
& (payments_autorecharge.c.top_up_countdown is not None)
92-
)
93-
.values(
94-
top_up_countdown=payments_autorecharge.c.top_up_countdown - 1,
95-
)
96-
.returning(payments_autorecharge.c.top_up_countdown)
97-
)

packages/postgres-database/tests/test_utils_payments_autorecharge.py

Lines changed: 6 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
from aiopg.sa.result import RowProxy
1313
from faker import Faker
1414
from pytest_simcore.helpers.rawdata_fakers import random_payment_method, utcnow
15-
from simcore_postgres_database import errors
1615
from simcore_postgres_database.models.payments_methods import (
1716
InitPromptAckFlowState,
1817
payments_methods,
@@ -47,19 +46,17 @@ async def _upsert_autorecharge(
4746
wallet_id,
4847
enabled,
4948
primary_payment_method_id,
50-
min_balance_in_usd,
5149
top_up_amount_in_usd,
52-
top_up_countdown,
50+
monthly_limit_in_usd,
5351
) -> RowProxy:
5452
# using this primary payment-method, create an autorecharge
5553
# NOTE: requires the entire
5654
stmt = AutoRechargeStmts.upsert_wallet_autorecharge(
5755
wallet_id=wallet_id,
5856
enabled=enabled,
5957
primary_payment_method_id=primary_payment_method_id,
60-
min_balance_in_usd=min_balance_in_usd,
6158
top_up_amount_in_usd=top_up_amount_in_usd,
62-
top_up_countdown=top_up_countdown,
59+
monthly_limit_in_usd=monthly_limit_in_usd,
6360
)
6461
row = await (await connection.execute(stmt)).first()
6562
assert row
@@ -71,12 +68,6 @@ async def _update_autorecharge(connection, wallet_id, **settings) -> int | None:
7168
return await connection.scalar(stmt)
7269

7370

74-
async def _decrease_countdown(connection, wallet_id) -> int | None:
75-
stmt = AutoRechargeStmts.decrease_wallet_autorecharge_countdown(wallet_id)
76-
# updates payments countdown
77-
return await connection.scalar(stmt)
78-
79-
8071
PaymentMethodRow: TypeAlias = RowProxy
8172

8273

@@ -123,41 +114,24 @@ async def test_payments_automation_workflow(
123114
wallet_id,
124115
enabled=True,
125116
primary_payment_method_id=payment_method_id,
126-
min_balance_in_usd=10,
127117
top_up_amount_in_usd=100,
128-
top_up_countdown=5,
118+
monthly_limit_in_usd=None,
129119
)
130120

131121
auto_recharge = await _get_auto_recharge(connection, wallet_id)
132122
assert auto_recharge is not None
133123
assert auto_recharge.primary_payment_method_id == payment_method_id
134124
assert auto_recharge.enabled is True
135125

136-
# countdown
137-
assert await _decrease_countdown(connection, wallet_id) == 4
138-
assert await _decrease_countdown(connection, wallet_id) == 3
139-
assert await _decrease_countdown(connection, wallet_id) == 2
140-
assert await _decrease_countdown(connection, wallet_id) == 1
141-
assert await _decrease_countdown(connection, wallet_id) == 0
142-
143-
with pytest.raises(errors.CheckViolation) as err_info:
144-
await _decrease_countdown(connection, wallet_id)
145-
146-
exc = err_info.value
147-
assert exc.pgerror
148-
assert "check_top_up_countdown_nonnegative" in exc.pgerror
149-
150126
# upsert: deactivate countdown
151127
auto_recharge = await _upsert_autorecharge(
152128
connection,
153129
wallet_id,
154130
enabled=True,
155131
primary_payment_method_id=payment_method_id,
156-
min_balance_in_usd=10,
157132
top_up_amount_in_usd=100,
158-
top_up_countdown=None, # <----
133+
monthly_limit_in_usd=10000, # <----
159134
)
160-
assert auto_recharge.top_up_countdown is None
135+
assert auto_recharge.monthly_limit_in_usd == 10000
161136

162-
await _update_autorecharge(connection, wallet_id, top_up_countdown=None)
163-
assert await _decrease_countdown(connection, wallet_id) is None
137+
await _update_autorecharge(connection, wallet_id, monthly_limit_in_usd=None)

services/docker-compose.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,8 +420,9 @@ services:
420420
TWILIO_COUNTRY_CODES_W_ALPHANUMERIC_SID_SUPPORT: ${TWILIO_COUNTRY_CODES_W_ALPHANUMERIC_SID_SUPPORT}
421421

422422
WEBSERVER_PAYMENTS: ${WEBSERVER_PAYMENTS}
423-
PAYMENTS_AUTORECHARGE_DEFAULT_MIN_BALANCE: ${PAYMENTS_AUTORECHARGE_DEFAULT_MIN_BALANCE}
423+
PAYMENTS_AUTORECHARGE_DEFAULT_MONTHLY_LIMIT: ${PAYMENTS_AUTORECHARGE_DEFAULT_MONTHLY_LIMIT}
424424
PAYMENTS_AUTORECHARGE_DEFAULT_TOP_UP_AMOUNT: ${PAYMENTS_AUTORECHARGE_DEFAULT_TOP_UP_AMOUNT}
425+
PAYMENTS_AUTORECHARGE_MIN_BALANCE_IN_CREDITS: ${PAYMENTS_AUTORECHARGE_MIN_BALANCE_IN_CREDITS}
425426
PAYMENTS_FAKE_COMPLETION_DELAY_SEC: ${PAYMENTS_FAKE_COMPLETION_DELAY_SEC}
426427
PAYMENTS_FAKE_COMPLETION: ${PAYMENTS_FAKE_COMPLETION}
427428
PAYMENTS_FAKE_GATEWAY_URL: ${PAYMENTS_GATEWAY_URL}

0 commit comments

Comments
 (0)