diff --git a/backend/src/configuration/environment.py b/backend/src/configuration/environment.py index a7625bb..a995c10 100644 --- a/backend/src/configuration/environment.py +++ b/backend/src/configuration/environment.py @@ -13,6 +13,11 @@ load_dotenv(override=True) @dataclass class Environment : + # Load supabase secrets supabase_url = os.environ['SUPABASE_URL'] supabase_admin_key = os.environ['SUPABASE_ADMIN_KEY'] - supabase_test_user_id = os.environ['SUPABASE_TEST_USER_ID'] \ No newline at end of file + supabase_test_user_id = os.environ['SUPABASE_TEST_USER_ID'] + + # Load paypal secrets + paypal_id_sandbox = os.environ['PAYPAL_ID_SANDBOX'] + paypal_key_sandbox = os.environ['PAYPAL_KEY_SANDBOX'] diff --git a/backend/src/payments/payment_handler.py b/backend/src/payments/payment_handler.py index e41f744..c682c79 100644 --- a/backend/src/payments/payment_handler.py +++ b/backend/src/payments/payment_handler.py @@ -4,6 +4,9 @@ from pydantic import BaseModel from fastapi import HTTPException import logging +import requests +from ..configuration.environment import Environment + # Model for payment request body class PaymentRequest(BaseModel): @@ -14,13 +17,22 @@ class PaymentRequest(BaseModel): # Payment handler class for managing PayPal payments -class PaymentHandler: +class PaypalHandler: - payment_id: str + # PayPal secrets + username = Environment.paypal_id_sandbox + password = Environment.paypal_key_sandbox - def __init__(self, transaction_details: PaymentRequest): + + + def __init__( + self, + transaction_details: PaymentRequest, + sandbox_mode: bool = False + ): self.details = transaction_details self.logger = logging.getLogger(__name__) + self.sandbox = sandbox_mode # Only support purchase of credit 'bundles': 10, 50 or 100 credits worth of trip generation def fetch_price(self) -> float: @@ -34,37 +46,40 @@ class PaymentHandler: self.logger.error(f"Unsupported currency: {self.details.currency}") return None - def create_paypal_payment(self) -> str: - """ - Creates a PayPal payment and returns the approval URL. - """ - price = self.fetch_price() - payment = paypalrestsdk.Payment({ - "intent": "sale", - "payer": { - "payment_method": "paypal" - }, - "transactions": [{ - "amount": { - "total": f"{price:.2f}", - "currency": self.details.currency - }, - "description": self.details.description - }], - "redirect_urls": { - "return_url": "http://localhost:8000/payment/success", - "cancel_url": "http://localhost:8000/payment/cancel" - } - }) - if payment.create(): - self.logger.info("Payment created successfully") - self.payment_id = payment.id + def validate(self): - # Get the approval URL and return it for the user to approve - for link in payment.links: - if link.rel == "approval_url": - return link.href - else: - self.logger.error(f"Failed to create payment: {payment.error}") - raise HTTPException(status_code=500, detail="Payment creation failed") + if self.sandbox : + validation_url = "https://api-m.sandbox.paypal.com/v1/oauth2/token" + else : + validation_url = "https://api-m.paypal.com/v1/oauth2/token" + + # payload for the validation request + validation_data = {'grant_type': 'client_credentials'} + + # pass the request + validation_response = requests.post( + url=validation_url, + data=validation_data, + auth=(self.username, self.password) + ) + + # TODO: continue here + + + pass + + def order(self): + + + pass + + def capture(self): + + + pass + + + def cancel(self): + + pass diff --git a/backend/src/payments/test.py b/backend/src/payments/test.py new file mode 100644 index 0000000..6950fd6 --- /dev/null +++ b/backend/src/payments/test.py @@ -0,0 +1,100 @@ +import requests +import json + +from ..configuration.environment import Environment + + + +# DOCUMENTATION AT : https://developer.paypal.com/api/rest/requests/ + +# username and password +username = Environment.paypal_id_sandbox +password = Environment.paypal_key_sandbox + + +######## STEP 1: Validation ######## +# url for validation post request +validation_url = "https://api-m.sandbox.paypal.com/v1/oauth2/token" +validation_url_prod = "https://api-m.paypal.com/v1/oauth2/token" + +# payload for the post request +validation_data = {'grant_type': 'client_credentials'} + +# pass the request +validation_response = requests.post( + url=validation_url, + data=validation_data, + auth=(username, password) +) + +# todo check status code + try except. Status code 201 ? +print(validation_response.text) +access_token = json.loads(validation_response.text)["access_token"] + + +######## STEP 2: Create Order ######## +# url for post request +order_url = "https://api-m.sandbox.paypal.com/v2/checkout/orders" +order_url_prod = "https://api-m.paypal.com/v2/checkout/orders" + +# payload for the request +order_data = { + "intent": "CAPTURE", + "purchase_units": [ + { + "items": [ + { + "name": "AnyWay Credits", + "description": "50 pack of credits", + "quantity": 1, + "unit_amount": { + "currency_code": "CHF", + "value": "5.00" + } + + } + ], + "amount": { + "currency_code": "CHF", + "value": "5.00", + "breakdown": { + "item_total": { + "currency_code": "CHF", + "value": "5.00" + } + } + } + } + ], + "application_context": { + "return_url": "https://anydev.info", + "cancel_url": "https://anydev.info" + } +} + +order_response = requests.post( + url=order_url, + json=order_data, + auth=(username, password) +) + +# todo check status code + try except +print(order_response.text) +order_id = json.loads(order_response.text)["id"] + + +######## STEP 3: capture payment +# url for post request +capture_url = f"https://api-m.sandbox.paypal.com/v2/checkout/orders/{order_id}/capture" +capture_url_prod = f"https://api-m.paypal.com/v2/checkout/orders/{order_id}/capture" + +capture_response = requests.post( + url=capture_url, + json={}, + auth=(username, password) +) + +# todo check status code + try except +print(capture_response.text) +# order_id = json.loads(response.text)["id"] +