Merge modifications for more separate backend functions #69
| @@ -13,6 +13,11 @@ load_dotenv(override=True) | |||||||
| @dataclass | @dataclass | ||||||
| class Environment : | class Environment : | ||||||
| 
					
					kscheidecker marked this conversation as resolved
					
				 | |||||||
|  |  | ||||||
|  |     # Load supabase secrets | ||||||
|     supabase_url = os.environ['SUPABASE_URL'] |     supabase_url = os.environ['SUPABASE_URL'] | ||||||
|     supabase_admin_key = os.environ['SUPABASE_ADMIN_KEY'] |     supabase_admin_key = os.environ['SUPABASE_ADMIN_KEY'] | ||||||
|     supabase_test_user_id = os.environ['SUPABASE_TEST_USER_ID'] |     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'] | ||||||
|   | |||||||
| @@ -4,6 +4,9 @@ from pydantic import BaseModel | |||||||
| from fastapi import HTTPException | from fastapi import HTTPException | ||||||
| import logging | import logging | ||||||
|  |  | ||||||
|  | import requests | ||||||
|  | from ..configuration.environment import Environment | ||||||
|  |  | ||||||
|  |  | ||||||
| # Model for payment request body | # Model for payment request body | ||||||
| class PaymentRequest(BaseModel): | class PaymentRequest(BaseModel): | ||||||
| @@ -14,13 +17,22 @@ class PaymentRequest(BaseModel): | |||||||
|  |  | ||||||
|  |  | ||||||
| # Payment handler class for managing PayPal payments | # 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.details = transaction_details | ||||||
|         self.logger = logging.getLogger(__name__) |         self.logger = logging.getLogger(__name__) | ||||||
|  |         self.sandbox = sandbox_mode | ||||||
|  |  | ||||||
|     # Only support purchase of credit 'bundles': 10, 50 or 100 credits worth of trip generation |     # Only support purchase of credit 'bundles': 10, 50 or 100 credits worth of trip generation | ||||||
|     def fetch_price(self) -> float: |     def fetch_price(self) -> float: | ||||||
| @@ -34,37 +46,40 @@ class PaymentHandler: | |||||||
|             self.logger.error(f"Unsupported currency: {self.details.currency}") |             self.logger.error(f"Unsupported currency: {self.details.currency}") | ||||||
|             return None |             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(): |     def validate(self): | ||||||
|             self.logger.info("Payment created successfully") |  | ||||||
|             self.payment_id = payment.id |  | ||||||
|  |  | ||||||
|             # Get the approval URL and return it for the user to approve |         if self.sandbox : | ||||||
|             for link in payment.links: |             validation_url = "https://api-m.sandbox.paypal.com/v1/oauth2/token" | ||||||
|                 if link.rel == "approval_url": |         else : | ||||||
|                     return link.href |             validation_url = "https://api-m.paypal.com/v1/oauth2/token" | ||||||
|         else: |  | ||||||
|             self.logger.error(f"Failed to create payment: {payment.error}") |         # payload for the validation request | ||||||
|             raise HTTPException(status_code=500, detail="Payment creation failed") |         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 | ||||||
|   | |||||||
							
								
								
									
										100
									
								
								backend/src/payments/test.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								backend/src/payments/test.py
									
									
									
									
									
										Normal file
									
								
							| @@ -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"] | ||||||
|  |  | ||||||
		Reference in New Issue
	
	Block a user
	
I like this.