Tesis 1.0.0
Loading...
Searching...
No Matches
services.py
Go to the documentation of this file.
1import logging
2import requests
3import mercadopago
4from django.conf import settings
5from payment_service.models import PaymentRequest, PaymentNotification
6from decimal import Decimal
7
8logger = logging.getLogger('payment_service')
9
11 """
12 Servicio para interactuar con el carrito del usuario en el backend principal
13 """
14 @staticmethod
15 def get_cart(user_token):
16 """
17 Obtiene el carrito del usuario desde el backend principal
18 """
19 try:
20 # Validación básica del token
21 if not user_token:
22 logger.error("Token de usuario vacío o no proporcionado")
23 return None
24
25 # Modo de prueba para debugging
26 if settings.DEBUG and "test" in user_token.lower():
27 logger.info(f"Usando datos de prueba para el carrito con token: {user_token[:10]}...")
28 return {
29 "productos": [
30 {
31 "id": 1,
32 "nombre": "Producto de Prueba 1",
33 "descripcion": "Descripción del producto 1",
34 "precio": 100.50,
35 "cantidad": 2
36 },
37 {
38 "id": 2,
39 "nombre": "Producto de Prueba 2",
40 "descripcion": "Descripción del producto 2",
41 "precio": 200.75,
42 "cantidad": 1
43 }
44 ],
45 "total": 401.75
46 }
47
48 url = f"{settings.MAIN_BACKEND_URL}/appCART/ver/"
49
50 # Determinar el formato del token (JWT o Token clásico)
51 if user_token.startswith('eyJ'): # Formato típico de JWT
52 headers = {"Authorization": f"Bearer {user_token}"}
53 logger.info("Usando formato de token JWT (Bearer)")
54 else:
55 headers = {"Authorization": f"Token {user_token}"}
56 logger.info("Usando formato de token clásico")
57 logger.info(f"Consultando carrito en: {url} con token: {user_token[:5]}...")
58 response = requests.get(url, headers=headers, timeout=10)
59
60 if response.status_code == 200:
61 response_data = response.json()
62
63 # Si la respuesta es un array, convertirla al formato esperado
64 if isinstance(response_data, list):
65 logger.info(f"Respuesta en formato de lista con {len(response_data)} productos")
66 cart_data = {
67 "productos": response_data,
68 "total": sum(float(item.get("precio", 0)) * int(item.get("cantidad", 0)) for item in response_data)
69 }
70 logger.info(f"Carrito convertido a formato interno con total: {cart_data['total']}")
71 return cart_data
72 else:
73 logger.info(f"Respuesta en formato de objeto")
74 return response_data
75 else:
76 logger.error(f"Error al obtener el carrito: {response.status_code} - {response.text}")
77 return None
78 except Exception as e:
79 logger.exception(f"Error al consultar el carrito: {str(e)}")
80 return None
81
82 @staticmethod
83 def confirm_order(user_token, payment_id):
84 """
85 Confirma el pedido en el backend principal
86 """
87 try:
88 url = f"{settings.MAIN_BACKEND_URL}/appCART/confirmar/"
89
90 # Determinar el formato del token (JWT o Token clásico)
91 if user_token.startswith('eyJ'): # Formato típico de JWT
92 headers = {"Authorization": f"Bearer {user_token}"}
93 logger.info("Usando formato de token JWT (Bearer) para confirmar pedido")
94 else:
95 headers = {"Authorization": f"Token {user_token}"}
96 logger.info("Usando formato de token clásico para confirmar pedido")
97
98 data = {"payment_id": payment_id}
99
100 logger.info(f"Confirmando pedido en: {url}")
101 response = requests.post(url, json=data, headers=headers, timeout=10)
102
103 if response.status_code in [200, 201]:
104 return True, response.json()
105 else:
106 logger.error(f"Error al confirmar el pedido: {response.status_code} - {response.text}")
107 return False, {"error": response.text}
108 except Exception as e:
109 logger.exception(f"Error al confirmar el pedido: {str(e)}")
110 return False, {"error": str(e)}
111
113 """
114 Servicio para interactuar con la API de Mercado Pago
115 """
116 def __init__(self):
117 self.sdk = mercadopago.SDK(settings.MERCADOPAGO_ACCESS_TOKEN)
118
119 def create_preference(self, items, external_reference, payer_email=None, notification_url=None, back_urls=None):
120 """
121 Crea una preferencia de pago en Mercado Pago y verifica que esté activa antes de devolver la URL
122 """
123 try:
124 # Construir los datos de la preferencia
125 preference_data = {
126 "items": items,
127 "external_reference": str(external_reference),
128 "back_urls": back_urls if back_urls else {
129 "success": "https://ispcfood.netlify.app/exito",
130 "failure": "https://ispcfood.netlify.app/error",
131 "pending": "https://ispcfood.netlify.app/pendiente"
132 },
133 "auto_return": "approved"
134 }
135 # Solo agregar notification_url si es una URL pública válida (no localhost ni 127.0.0.1)
136 if notification_url and not (notification_url.startswith('http://127.0.0.1') or notification_url.startswith('http://localhost')):
137 preference_data["notification_url"] = notification_url
138 else:
139 logger.info(f"No se envía notification_url a Mercado Pago por ser local: {notification_url}")
140 # Agregar datos del comprador si están disponibles
141 if payer_email:
142 preference_data["payer"] = {
143 "email": payer_email
144 }
145 logger.info(f"Creando preferencia de pago: {preference_data}")
146 preference_response = self.sdk.preference().create(preference_data)
147 logger.info(f"Respuesta cruda de Mercado Pago al crear preferencia: {preference_response}")
148 # Si hay error explícito, loguear y devolver None
149 if preference_response.get('status') != 201:
150 logger.error(f"Error al crear preferencia: status {preference_response.get('status')}, detalle: {preference_response.get('response')}")
151 return None
152 pref = preference_response["response"]
153 # Verificar estado de la preferencia SOLO si el campo status existe
154 pref_id = pref.get("id")
155 if pref_id:
156 status_resp = self.sdk.preference().get(pref_id)
157 status_value = status_resp["response"].get("status")
158 if status_value is not None and status_value != "active":
159 logger.error(f"Preferencia {pref_id} no está activa: {status_value}")
160 return None
161 return pref
162 except Exception as e:
163 logger.exception(f"Error al crear preferencia de pago: {str(e)}")
164 return None
165
166 def process_cart_to_items(self, cart_data):
167 """
168 Procesa los datos del carrito y los convierte al formato requerido por Mercado Pago
169 """
170 try:
171 if not cart_data:
172 logger.error("Datos del carrito inválidos o vacíos")
173 return []
174
175 # Si es una lista (formato de array del backend principal)
176 if isinstance(cart_data, list):
177 items = []
178 for producto in cart_data:
179 item = {
180 "id": str(producto.get("id", "")),
181 "title": producto.get("producto", "Producto"),
182 "description": producto.get("imageURL", ""),
183 "quantity": int(producto.get("cantidad", 1)),
184 "unit_price": float(producto.get("precio", 0)),
185 "currency_id": "ARS" # Ajustar según el país
186 }
187 items.append(item)
188 return items
189
190 # Si es un diccionario con "productos" (formato actual esperado)
191 elif isinstance(cart_data, dict) and "productos" in cart_data:
192 items = []
193 for producto in cart_data.get("productos", []):
194 item = {
195 "id": str(producto.get("id")),
196 "title": producto.get("nombre", "Producto"),
197 "description": producto.get("descripcion", ""),
198 "quantity": int(producto.get("cantidad", 1)),
199 "unit_price": float(producto.get("precio", 0)),
200 "currency_id": "ARS" # Ajustar según el país
201 }
202 items.append(item)
203 return items
204 else:
205 logger.error("Formato de carrito no reconocido")
206 return []
207 except Exception as e:
208 logger.exception(f"Error al procesar carrito a items: {str(e)}")
209 return []
210
211 def get_payment(self, payment_id):
212 """
213 Consulta el estado de un pago en Mercado Pago
214 """
215 try:
216 logger.info(f"Consultando pago {payment_id}")
217 payment_response = self.sdk.payment().get(payment_id)
218
219 if payment_response["status"] == 200:
220 return payment_response["response"]
221 else:
222 logger.error(f"Error al consultar pago: {payment_response['status']}")
223 return None
224 except Exception as e:
225 logger.exception(f"Error al consultar pago: {str(e)}")
226 return None
confirm_order(user_token, payment_id)
Definition services.py:83
create_preference(self, items, external_reference, payer_email=None, notification_url=None, back_urls=None)
Definition services.py:119