Skip to content

Commit 7adc9f4

Browse files
Merge pull request #31 from Backendly/payment
Payment
2 parents cf820f7 + fc19741 commit 7adc9f4

24 files changed

+238
-880
lines changed

api/main.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
)
1313
import os
1414
import uvicorn
15-
from jobs.payment_jobs import receive_orders
1615
import sentry_sdk
1716
from dotenv import load_dotenv
1817

@@ -33,7 +32,7 @@
3332
)
3433

3534

36-
receive_orders.delay()
35+
# recieve_orders.delay()
3736

3837

3938
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True)

api/v1/crud/account_crud.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
from sqlalchemy.ext.asyncio import AsyncSession
22
from typing import Any
33
from services.stripe_config import stripe
4-
from fastapi import Request, HTTPException, Depends
4+
from fastapi import Request, HTTPException
55
from datetime import datetime
66
from typing import Dict
77
from db.session import redis_instance
88
import os
9+
from fastapi.background import BackgroundTasks
10+
from backgrounds import save_connected_account
911

1012

1113
async def create_connected_account(
1214
data: Request,
1315
session: AsyncSession,
1416
validated_developer: Dict[str, Any],
17+
background_tasks: BackgroundTasks,
1518
):
1619
"""Creates a connected account"""
1720
data = await data.json()
@@ -45,6 +48,8 @@ async def create_connected_account(
4548
status_code=500,
4649
detail=f"An error occurred while creating the connected account.{e}",
4750
)
51+
data["account_id"] = account["id"]
52+
background_tasks.add_task(save_connected_account, data, session, developer_id)
4853

4954
full_onboard_url = stripe.AccountLink.create(
5055
account=account["id"],

api/v1/crud/payment_method_crud.py

Lines changed: 33 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,45 @@
11
from models.payment_method_model import PaymentMethod
22
from services.stripe_config import stripe
33
from sqlalchemy.ext.asyncio import AsyncSession
4-
from fastapi import HTTPException
4+
from fastapi import HTTPException, Request
55
from sqlalchemy.future import select
6-
from ..schema.payment_method_schema import (
7-
PaymentMethodCreate,
8-
PaymentMethodInDB,
9-
PaymentMethodType,
10-
)
6+
from typing import Dict
117

128

139
async def create_payment_method(
14-
payment_method: PaymentMethodCreate, session: AsyncSession
10+
data: Request,
11+
session: AsyncSession,
12+
validated_developer: Dict | str,
13+
validated_user: Dict | str,
14+
validated_app: Dict | str,
1515
):
1616
"""Creates a new payment method"""
17-
payment_method_dict = payment_method.model_dump()
18-
payment_method_type = payment_method_dict["type"]
19-
payment_method_details = payment_method_dict["details"]
20-
21-
if payment_method_type == PaymentMethodType.card:
22-
try:
23-
payment_method_stripe = await stripe.PaymentMethod.create(
24-
type="card",
25-
card={
26-
"number": payment_method_details["card_number"],
27-
"exp_month": payment_method_details["exp_month"],
28-
"exp_year": payment_method_details["exp_year"],
29-
"cvc": payment_method_details["card_cvc"],
30-
},
31-
)
32-
except Exception as e:
33-
raise HTTPException(
34-
status_code=500,
35-
detail=f"An error occurred while creating the payment method.{e}",
36-
)
37-
new_payment_method = PaymentMethod(
38-
id=payment_method_stripe["id"],
39-
type=payment_method_type,
40-
details={
41-
"card_last_four": payment_method_stripe["last4"],
42-
"card_type": payment_method_stripe["brand"],
43-
"exp_month": payment_method_stripe["exp_month"],
44-
"exp_year": payment_method_stripe["exp_year"],
45-
},
46-
)
47-
17+
developer_id = (
18+
validated_developer.get("developer_id")
19+
if type(validated_developer) == dict
20+
else validated_developer
21+
)
22+
user_id = (
23+
validated_user.get("user_id")
24+
if type(validated_user) == dict
25+
else validated_user
26+
)
27+
app_id = (
28+
validated_app.get("app_id") if type(validated_app) == dict else validated_app
29+
)
30+
payment_method_dict = await data.json()
31+
payment_method_type = payment_method_dict.get("type")
32+
preffered = payment_method_dict.get("preferred", False)
33+
payment_method_id = payment_method_dict.get("payment_method_id", None)
34+
35+
new_payment_method = PaymentMethod(
36+
payment_method_id=payment_method_id,
37+
user_id=user_id,
38+
app_id=app_id,
39+
developer_id=developer_id,
40+
type=payment_method_type,
41+
preferred=preffered,
42+
)
4843
try:
4944
session.add(new_payment_method)
5045
await session.commit()
@@ -57,56 +52,3 @@ async def create_payment_method(
5752
)
5853

5954
return new_payment_method
60-
61-
62-
async def get_payment_methods(session: AsyncSession, limit: int, offset: int):
63-
"""Returns all payment methods"""
64-
result = await session.execute(select(PaymentMethod).limit(limit).offset(offset))
65-
results = result.scalars().all()
66-
new_results = []
67-
for result in results:
68-
result = PaymentMethodInDB.model_validate(result)
69-
result = result.model_dump()
70-
del result["details"]["card_cvc"]
71-
result["details"]["card_last_four"] = result["details"]["card_number"][-4:]
72-
del result["details"]["card_number"]
73-
new_results.append(result)
74-
75-
return new_results
76-
77-
78-
async def get_payment_method(id: str, session: AsyncSession):
79-
"""Returns a payment method by id"""
80-
result = await session.execute(
81-
select(PaymentMethod).filter(PaymentMethod.id == id),
82-
)
83-
payment_method = result.scalars().first()
84-
if not payment_method:
85-
raise HTTPException(
86-
status_code=404,
87-
detail="Payment method not found",
88-
)
89-
result = payment_method
90-
result = PaymentMethodInDB.model_validate(result)
91-
result = result.model_dump()
92-
del result["details"]["card_cvc"]
93-
result["details"]["card_last_four"] = result["details"]["card_number"][-4:]
94-
del result["details"]["card_number"]
95-
96-
return PaymentMethodInDB(**result)
97-
98-
99-
async def delete_payment_method(id: str, session: AsyncSession):
100-
"""Deletes a payment method"""
101-
payment_method = await get_payment_method(id, session)
102-
if not payment_method:
103-
raise HTTPException(
104-
status_code=404,
105-
detail="Payment method not found",
106-
)
107-
payment_method = await session.execute(
108-
select(PaymentMethod).filter(PaymentMethod.id == id)
109-
)
110-
payment_method = payment_method.scalars().first()
111-
await session.delete(payment_method)
112-
await session.commit()

api/v1/routes/account_routes.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,12 @@ async def connected_account(
4949
data, background_tasks=background_tasks
5050
)
5151
data_response = await create_connected_account(
52-
data, session, validated_developer
52+
data,
53+
session,
54+
validated_developer,
55+
background_tasks=background_tasks,
5356
)
57+
5458
onboarding_url = data_response["onboarding_url"]
5559
del data_response["onboarding_url"]
5660
links = {

api/v1/routes/payment_method_routes.py

Lines changed: 22 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -2,131 +2,39 @@
22
from sqlalchemy.ext.asyncio import AsyncSession
33
from models.payment_method_model import PaymentMethod
44
from fastapi import HTTPException
5+
from fastapi.background import BackgroundTasks
56
from sqlalchemy.future import select
67
from sqlalchemy import func
78
from typing import Annotated
8-
from ..crud.payment_method_crud import (
9-
create_payment_method,
10-
get_payment_methods,
11-
get_payment_method,
12-
delete_payment_method,
13-
)
14-
from utils import validate_developer, validate_user
15-
from ..schema.payment_method_schema import (
16-
PaymentMethodCreate,
17-
PaymentMethodInDB,
18-
PaymentMethodReturnDetail,
19-
PaymentMethodReturnListing,
20-
ListingLink,
21-
ListingMeta,
22-
)
9+
from utils import validate_developer, validate_user, validate_app
2310
from db.session import get_db
11+
from ..crud.payment_method_crud import create_payment_method
12+
from ..schema.payment_method_schema import PaymentMethodReturnDetail
2413

2514
router = APIRouter(prefix="/api/v1", tags=["Payment Methods"])
2615

2716

28-
@router.post(
29-
"/payment-methods",
30-
response_model=PaymentMethodReturnDetail,
31-
status_code=201,
32-
)
17+
@router.post("/payment-methods", status_code=201)
3318
async def add_payment_method(
34-
request: Request,
35-
payment_method: PaymentMethodCreate,
19+
data: Request,
20+
background_tasks: BackgroundTasks,
3621
session: AsyncSession = Depends(get_db),
3722
):
38-
"""Creates a new payment method"""
39-
data = await create_payment_method(payment_method, session=session)
40-
self_link = str(request.url_for("retrieve_payment_method", id=data.id))
41-
return {
42-
"data": data,
43-
"meta": {
44-
"message": "Payment method created successfully",
45-
"status_code": 201,
46-
},
47-
"links": {
48-
"self": self_link,
49-
},
50-
}
51-
52-
53-
@router.get("/payment-methods", response_model=PaymentMethodReturnListing)
54-
async def retrieve_payment_methods(
55-
page: Annotated[int, Query(ge=1)] = 1,
56-
per_page: Annotated[int, Query(ge=1, le=100)] = 20,
57-
session: AsyncSession = Depends(get_db),
58-
request: Request = None,
59-
):
60-
"""Retrieve all user"""
61-
offset = (page - 1) * per_page
62-
total_items_result = await session.execute(
63-
select(func.count()).select_from(PaymentMethod)
23+
"""Adds a new payment method"""
24+
validated_developer = await validate_developer(
25+
data, background_tasks=background_tasks
6426
)
65-
total_items = total_items_result.scalar() if total_items_result else 0
66-
67-
if total_items == 0:
68-
raise HTTPException(
69-
status_code=404,
70-
detail="No payment methods found",
71-
)
72-
total_pages = (total_items + per_page - 1) // per_page
73-
74-
data = await get_payment_methods(session=session, limit=per_page, offset=offset)
75-
76-
base_url = str(request.url).split("?")[0]
77-
78-
links = ListingLink(
79-
prev=f"{base_url}?page={page - 1}&per_page={per_page}" if page > 1 else None,
80-
self=f"{base_url}?page={page}&per_page={per_page}",
81-
next=(
82-
f"{base_url}?page={page + 1}&per_page={per_page}"
83-
if page < total_pages
84-
else None
85-
),
86-
first=f"{base_url}?page=1&per_page={per_page}",
87-
last=f"{base_url}?page={total_pages}&per_page={per_page}",
27+
validated_user = await validate_user(data, background_tasks=background_tasks)
28+
validated_app = await validate_app(data, background_tasks=background_tasks)
29+
payment_method = await create_payment_method(
30+
data=data,
31+
session=session,
32+
validated_app=validated_app,
33+
validated_developer=validated_developer,
34+
validated_user=validated_user,
8835
)
89-
meta = ListingMeta(
90-
message="Payment methods retrieved successfully",
91-
status_code=200,
92-
page=page,
93-
per_page=per_page,
94-
total_pages=total_pages,
95-
total_items=total_items,
36+
return PaymentMethodReturnDetail(
37+
links={"self": str(data.url)},
38+
data=payment_method,
39+
meta={"status_code": 201},
9640
)
97-
98-
return PaymentMethodReturnListing(links=links, meta=meta, data=data)
99-
100-
101-
@router.get("/payment-methods/{id}", response_model=PaymentMethodReturnDetail)
102-
async def retrieve_payment_method(
103-
request: Request,
104-
id: str,
105-
session: AsyncSession = Depends(get_db),
106-
):
107-
"""Retrieves a payment method"""
108-
data = await get_payment_method(id=id, session=session)
109-
self_link = str(request.url_for("retrieve_payment_method", id=data.id))
110-
return {
111-
"data": data,
112-
"meta": {
113-
"message": "Payment method retrieved successfully",
114-
"status_code": 200,
115-
},
116-
"links": {
117-
"self": self_link,
118-
},
119-
}
120-
121-
122-
@router.delete("/payment-methods/{id}")
123-
async def remove_payment_method(
124-
id: str,
125-
session: AsyncSession = Depends(get_db),
126-
):
127-
"""Deletes a payment method"""
128-
await delete_payment_method(id=id, session=session)
129-
return {
130-
"message": "Payment method deleted successfully",
131-
"status_code": 200,
132-
}

0 commit comments

Comments
 (0)