Skip to content

Commit 825c22a

Browse files
✨ introduce licensed_items_purchases endpoints 🗃️ (#6928)
On behalf of @matusdrobuliak66
1 parent a35576c commit 825c22a

File tree

54 files changed

+2002
-247
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+2002
-247
lines changed

api/specs/web-server/_catalog_licensed_items.py renamed to api/specs/web-server/_licensed_items.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,8 @@
1414
from models_library.generics import Envelope
1515
from models_library.rest_error import EnvelopedError
1616
from simcore_service_webserver._meta import API_VTAG
17-
from simcore_service_webserver.catalog.licenses._exceptions_handlers import (
18-
_TO_HTTP_ERROR_MAP,
19-
)
20-
from simcore_service_webserver.catalog.licenses._models import (
17+
from simcore_service_webserver.licenses._exceptions_handlers import _TO_HTTP_ERROR_MAP
18+
from simcore_service_webserver.licenses._models import (
2119
LicensedItemsBodyParams,
2220
LicensedItemsListQueryParams,
2321
LicensedItemsPathParams,
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
""" Helper script to generate OAS automatically
2+
"""
3+
4+
# pylint: disable=redefined-outer-name
5+
# pylint: disable=unused-argument
6+
# pylint: disable=unused-variable
7+
# pylint: disable=too-many-arguments
8+
9+
from typing import Annotated
10+
11+
from _common import as_query
12+
from fastapi import APIRouter, Depends
13+
from models_library.api_schemas_webserver.licensed_items_purchases import (
14+
LicensedItemPurchaseGet,
15+
)
16+
from models_library.generics import Envelope
17+
from models_library.rest_error import EnvelopedError
18+
from models_library.rest_pagination import Page
19+
from simcore_service_webserver._meta import API_VTAG
20+
from simcore_service_webserver.licenses._exceptions_handlers import _TO_HTTP_ERROR_MAP
21+
from simcore_service_webserver.licenses._models import (
22+
LicensedItemsPurchasesListQueryParams,
23+
LicensedItemsPurchasesPathParams,
24+
)
25+
from simcore_service_webserver.wallets._handlers import WalletsPathParams
26+
27+
router = APIRouter(
28+
prefix=f"/{API_VTAG}",
29+
tags=[
30+
"licenses",
31+
],
32+
responses={
33+
i.status_code: {"model": EnvelopedError} for i in _TO_HTTP_ERROR_MAP.values()
34+
},
35+
)
36+
37+
38+
@router.get(
39+
"/wallets/{wallet_id}/licensed-items-purchases",
40+
response_model=Page[LicensedItemPurchaseGet],
41+
tags=["wallets"],
42+
)
43+
async def list_wallet_licensed_items_purchases(
44+
_path: Annotated[WalletsPathParams, Depends()],
45+
_query: Annotated[as_query(LicensedItemsPurchasesListQueryParams), Depends()],
46+
):
47+
...
48+
49+
50+
@router.get(
51+
"/licensed-items-purchases/{licensed_item_purchase_id}",
52+
response_model=Envelope[LicensedItemPurchaseGet],
53+
)
54+
async def get_licensed_item_purchase(
55+
_path: Annotated[LicensedItemsPurchasesPathParams, Depends()],
56+
):
57+
...

api/specs/web-server/openapi.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,12 @@
3232
"_announcements",
3333
"_catalog",
3434
"_catalog_tags", # MUST BE after _catalog
35-
"_catalog_licensed_items",
3635
"_computations",
3736
"_exporter",
3837
"_folders",
3938
"_long_running_tasks",
39+
"_licensed_items",
40+
"_licensed_items_purchases",
4041
"_metamodeling",
4142
"_nih_sparc",
4243
"_nih_sparc_redirections",
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
from datetime import datetime
2+
from decimal import Decimal
3+
from typing import NamedTuple
4+
5+
from models_library.licensed_items import LicensedItemID
6+
from models_library.products import ProductName
7+
from models_library.resource_tracker import PricingUnitCostId
8+
from models_library.resource_tracker_licensed_items_purchases import (
9+
LicensedItemPurchaseID,
10+
)
11+
from models_library.users import UserID
12+
from models_library.wallets import WalletID
13+
from pydantic import BaseModel, ConfigDict, PositiveInt
14+
15+
16+
class LicensedItemPurchaseGet(BaseModel):
17+
licensed_item_purchase_id: LicensedItemPurchaseID
18+
product_name: ProductName
19+
licensed_item_id: LicensedItemID
20+
wallet_id: WalletID
21+
wallet_name: str
22+
pricing_unit_cost_id: PricingUnitCostId
23+
pricing_unit_cost: Decimal
24+
start_at: datetime
25+
expire_at: datetime
26+
num_of_seats: int
27+
purchased_by_user: UserID
28+
purchased_at: datetime
29+
modified: datetime
30+
31+
model_config = ConfigDict(
32+
json_schema_extra={
33+
"examples": [
34+
{
35+
"licensed_item_purchase_id": "beb16d18-d57d-44aa-a638-9727fa4a72ef",
36+
"product_name": "osparc",
37+
"licensed_item_id": "303942ef-6d31-4ba8-afbe-dbb1fce2a953",
38+
"wallet_id": 1,
39+
"wallet_name": "My Wallet",
40+
"pricing_unit_cost_id": 1,
41+
"pricing_unit_cost": 10,
42+
"start_at": "2023-01-11 13:11:47.293595",
43+
"expire_at": "2023-01-11 13:11:47.293595",
44+
"num_of_seats": 1,
45+
"purchased_by_user": 1,
46+
"purchased_at": "2023-01-11 13:11:47.293595",
47+
"modified": "2023-01-11 13:11:47.293595",
48+
}
49+
]
50+
}
51+
)
52+
53+
54+
class LicensedItemsPurchasesPage(NamedTuple):
55+
items: list[LicensedItemPurchaseGet]
56+
total: PositiveInt
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from datetime import datetime
2+
from decimal import Decimal
3+
from typing import NamedTuple
4+
5+
from models_library.licensed_items import LicensedItemID
6+
from models_library.products import ProductName
7+
from models_library.resource_tracker import PricingUnitCostId
8+
from models_library.resource_tracker_licensed_items_purchases import (
9+
LicensedItemPurchaseID,
10+
)
11+
from models_library.users import UserID
12+
from models_library.wallets import WalletID
13+
from pydantic import PositiveInt
14+
15+
from ._base import OutputSchema
16+
17+
18+
class LicensedItemPurchaseGet(OutputSchema):
19+
licensed_item_purchase_id: LicensedItemPurchaseID
20+
product_name: ProductName
21+
licensed_item_id: LicensedItemID
22+
wallet_id: WalletID
23+
pricing_unit_cost_id: PricingUnitCostId
24+
pricing_unit_cost: Decimal
25+
start_at: datetime
26+
expire_at: datetime
27+
num_of_seats: int
28+
purchased_by_user: UserID
29+
purchased_at: datetime
30+
modified_at: datetime
31+
32+
33+
class LicensedItemPurchaseGetPage(NamedTuple):
34+
items: list[LicensedItemPurchaseGet]
35+
total: PositiveInt

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

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,59 @@ class WalletGet(OutputSchema):
2020
created: datetime
2121
modified: datetime
2222

23-
model_config = ConfigDict(from_attributes=True, frozen=False)
23+
model_config = ConfigDict(
24+
from_attributes=True,
25+
frozen=False,
26+
json_schema_extra={
27+
"examples": [
28+
{
29+
"wallet_id": 1,
30+
"name": "My wallet",
31+
"description": "My description",
32+
"owner": 1,
33+
"thumbnail": "https://example.com/payment-method/form",
34+
"status": "ACTIVE",
35+
"created": "2024-03-25T00:00:00",
36+
"modified": "2024-03-25T00:00:00",
37+
}
38+
]
39+
},
40+
)
2441

2542

2643
class WalletGetWithAvailableCredits(WalletGet):
2744
available_credits: Decimal
2845

46+
model_config = ConfigDict(
47+
json_schema_extra={
48+
"examples": [
49+
{
50+
**WalletGet.model_config["json_schema_extra"]["examples"][0], # type: ignore
51+
"available_credits": 10.5,
52+
}
53+
]
54+
}
55+
)
56+
2957

3058
class WalletGetPermissions(WalletGet):
3159
read: bool
3260
write: bool
3361
delete: bool
3462

63+
model_config = ConfigDict(
64+
json_schema_extra={
65+
"examples": [
66+
{
67+
**WalletGet.model_config["json_schema_extra"]["examples"][0], # type: ignore
68+
"read": True,
69+
"write": True,
70+
"delete": True,
71+
}
72+
]
73+
}
74+
)
75+
3576

3677
class CreateWalletBodyParams(OutputSchema):
3778
name: str

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class CreditTransactionStatus(StrAutoEnum):
4848
class CreditClassification(StrAutoEnum):
4949
ADD_WALLET_TOP_UP = auto() # user top up credits
5050
DEDUCT_SERVICE_RUN = auto() # computational/dynamic service run costs)
51+
DEDUCT_LICENSE_PURCHASE = auto()
5152

5253

5354
class PricingPlanClassification(StrAutoEnum):
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from datetime import datetime
2+
from decimal import Decimal
3+
from typing import TypeAlias
4+
from uuid import UUID
5+
6+
from pydantic import BaseModel, ConfigDict
7+
8+
from .licensed_items import LicensedItemID
9+
from .products import ProductName
10+
from .resource_tracker import PricingPlanId, PricingUnitCostId, PricingUnitId
11+
from .users import UserID
12+
from .wallets import WalletID
13+
14+
LicensedItemPurchaseID: TypeAlias = UUID
15+
16+
17+
class LicensedItemsPurchasesCreate(BaseModel):
18+
product_name: ProductName
19+
licensed_item_id: LicensedItemID
20+
wallet_id: WalletID
21+
wallet_name: str
22+
pricing_plan_id: PricingPlanId
23+
pricing_unit_id: PricingUnitId
24+
pricing_unit_cost_id: PricingUnitCostId
25+
pricing_unit_cost: Decimal
26+
start_at: datetime
27+
expire_at: datetime
28+
num_of_seats: int
29+
purchased_by_user: UserID
30+
user_email: str
31+
purchased_at: datetime
32+
33+
model_config = ConfigDict(from_attributes=True)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""add cols to licensed_items_purchases table 3
2+
3+
Revision ID: 77ac824a77ff
4+
Revises: d68b8128c23b
5+
Create Date: 2024-12-10 16:42:14.041313+00:00
6+
7+
"""
8+
import sqlalchemy as sa
9+
from alembic import op
10+
from sqlalchemy.dialects import postgresql
11+
12+
# revision identifiers, used by Alembic.
13+
revision = "77ac824a77ff"
14+
down_revision = "d68b8128c23b"
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade():
20+
# ### commands auto generated by Alembic - please adjust! ###
21+
op.add_column(
22+
"resource_tracker_credit_transactions",
23+
sa.Column(
24+
"licensed_item_purchase_id", postgresql.UUID(as_uuid=True), nullable=True
25+
),
26+
)
27+
# ### end Alembic commands ###
28+
op.execute(
29+
sa.DDL(
30+
"ALTER TYPE credittransactionclassification ADD VALUE 'DEDUCT_LICENSE_PURCHASE'"
31+
)
32+
)
33+
34+
35+
def downgrade():
36+
# ### commands auto generated by Alembic - please adjust! ###
37+
op.drop_column("resource_tracker_credit_transactions", "licensed_item_purchase_id")
38+
# ### end Alembic commands ###
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
"""add cols to licensed_items_purchases table
2+
3+
Revision ID: 8fa15c4c3977
4+
Revises: 5e27063c3ac9
5+
Create Date: 2024-12-10 06:42:23.319239+00:00
6+
7+
"""
8+
import sqlalchemy as sa
9+
from alembic import op
10+
11+
# revision identifiers, used by Alembic.
12+
revision = "8fa15c4c3977"
13+
down_revision = "5e27063c3ac9"
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+
"resource_tracker_licensed_items_purchases",
22+
sa.Column("wallet_name", sa.String(), nullable=False),
23+
)
24+
op.add_column(
25+
"resource_tracker_licensed_items_purchases",
26+
sa.Column("pricing_unit_cost_id", sa.BigInteger(), nullable=False),
27+
)
28+
op.add_column(
29+
"resource_tracker_licensed_items_purchases",
30+
sa.Column("pricing_unit_cost", sa.Numeric(scale=2), nullable=True),
31+
)
32+
op.add_column(
33+
"resource_tracker_licensed_items_purchases",
34+
sa.Column("num_of_seats", sa.SmallInteger(), nullable=False),
35+
)
36+
# ### end Alembic commands ###
37+
38+
39+
def downgrade():
40+
# ### commands auto generated by Alembic - please adjust! ###
41+
op.drop_column("resource_tracker_licensed_items_purchases", "num_of_seats")
42+
op.drop_column("resource_tracker_licensed_items_purchases", "pricing_unit_cost")
43+
op.drop_column("resource_tracker_licensed_items_purchases", "pricing_unit_cost_id")
44+
op.drop_column("resource_tracker_licensed_items_purchases", "wallet_name")
45+
# ### end Alembic commands ###

0 commit comments

Comments
 (0)