Skip to content

Commit 526e210

Browse files
authored
Feat/#3 결제 요청 (#7)
## 작업 내역 (관련 이슈) - 사용자의 XRPL 지갑 seed로 결제 트랜잭션을 서명 및 전송하고, 파일 판매자에게 XRP를 송금하며, RLUSD 할인 및 거래 이력을 반영하는 전체 결제 로직입니다. ## 특이 사항 -
2 parents 9b5a324 + 24b57e4 commit 526e210

15 files changed

Lines changed: 758 additions & 15 deletions

poetry.lock

Lines changed: 426 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ boto3 = "^1.37.16"
1515
botocore = "^1.37.16"
1616
httpx = "^0.28.1"
1717
dotenv = "^0.9.9"
18+
xrpl-py = "^4.1.0"
19+
pymongo = "^4.11.3"
20+
motor = "^3.7.0"
1821

1922
[build-system]
2023
requires = ["poetry-core"]

src/main/config/XrplConfig.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import os
2+
from dotenv import load_dotenv
3+
import xrpl
4+
5+
load_dotenv()
6+
7+
XRPL_RPC_URL = os.getenv("XRPL_RPC_URL")
8+
9+
client = xrpl.clients.JsonRpcClient(XRPL_RPC_URL)

src/main/config/mongodb.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import os
2+
from dotenv import load_dotenv
3+
from pymongo import MongoClient
4+
5+
load_dotenv()
6+
7+
MONGODB_URL = os.getenv("MONGODB_URL")
8+
9+
def get_mongo_client() -> MongoClient:
10+
return MongoClient(MONGODB_URL + "?retryWrites=true")
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from pydantic import BaseModel
2+
3+
class PaymentsRequestDto(BaseModel):
4+
file_id: str

src/main/payments/dto/__init__.py

Whitespace-only changes.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
from pymongo import MongoClient
2+
from src.main.config.mongodb import get_mongo_client
3+
4+
class PaymentsRepository:
5+
def __init__(self):
6+
client: MongoClient = get_mongo_client()
7+
self.db = client["xrpedia-data"]
8+
self.wallets_collection = self.db["wallets"]
9+
self.document_collection = self.db["document_collection"]
10+
self.transactions_collection = self.db["transactions"]
11+
12+
# MongoDB에서 user_id 기반으로 XRPL 지갑 정보 조회
13+
def get_user_wallet(self, user_id: str):
14+
return self.wallets_collection.find_one({"user_id": user_id}, {"_id": 0, "address": 1, "seed": 1})
15+
16+
# MongoDB에서 파일 정보 전체 조회 (price + owner_id 포함)
17+
def get_file_info(self, file_id: str):
18+
return self.document_collection.find_one(
19+
{"file_id": file_id},
20+
{"_id": 0, "price": 1, "uploader_id": 1}
21+
)
22+
23+
# MongoDB에서 파일 가격 조회
24+
def get_file_price(self, file_id: str):
25+
file_info = self.document_collection.find_one(
26+
{"file_id": file_id},
27+
{"_id": 0, "price": 1}
28+
)
29+
return file_info["price"] if file_info else None
30+
31+
def get_user_profile(self, user_id: str):
32+
return self.wallets_collection.find_one(
33+
{"user_id": user_id},
34+
{"_id": 0, "profile": 1}
35+
)
36+
37+
def update_user_rlusd(self, user_id: str, new_rlusd: int):
38+
self.wallets_collection.update_one(
39+
{"user_id": user_id},
40+
{"$set": {"rlusd": new_rlusd}}
41+
)
42+
43+
def is_transaction_exist(self, user_id: str, file_id: str):
44+
print(f"Checking if transaction exists for user_id: {user_id}, file_id: {file_id}")
45+
transaction = self.transactions_collection.find_one(
46+
{"user_id": user_id, "file_id": file_id}
47+
)
48+
if transaction:
49+
print(f"Transaction found: {transaction}")
50+
else:
51+
print("Transaction not found")
52+
return transaction is not None
53+
54+
def save_transaction(self, tx_data: dict):
55+
print(f"Saving transaction: {tx_data}")
56+
self.transactions_collection.insert_one(tx_data)

src/main/payments/repository/__init__.py

Whitespace-only changes.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from fastapi import APIRouter, Depends
2+
from fastapi.concurrency import run_in_threadpool
3+
from src.main.payments.dto.PaymentsRequestDto import PaymentsRequestDto
4+
from src.main.payments.service.PaymentsService import PaymentsService
5+
from src.main.auth.dependencies import get_current_user
6+
import uuid
7+
8+
router = APIRouter(
9+
prefix="/payments",
10+
tags=["payments"],
11+
)
12+
13+
@router.post("/_request")
14+
async def request_payment(
15+
request: PaymentsRequestDto,
16+
user_id: uuid.UUID = Depends(get_current_user),
17+
payments_service: PaymentsService = Depends()
18+
):
19+
return await run_in_threadpool(
20+
payments_service.request_payment, str(user_id), request.file_id
21+
)

src/main/payments/router/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)