refactor: separate standalone and managed room configs
- veins → shunts rename - add cfg/standalone/ and cfg/<room>/ structure - remove old data/*.json (moved to cfg/<room>/data/) - update build.py and ctrl scripts
This commit is contained in:
263
artery/shunts/mercadopago/README.md
Normal file
263
artery/shunts/mercadopago/README.md
Normal file
@@ -0,0 +1,263 @@
|
||||
# MercadoPago (MOCK) Vein
|
||||
|
||||
Mock MercadoPago API for testing - simulates payment processing without hitting the real MercadoPago API.
|
||||
|
||||
## Purpose
|
||||
|
||||
Enables testing of MercadoPago integration without:
|
||||
- Creating real payments
|
||||
- Connecting real MercadoPago accounts
|
||||
- Exposing credentials
|
||||
- Consuming API quotas
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
pip install -r requirements.txt
|
||||
|
||||
# Start the mock server
|
||||
python run.py
|
||||
|
||||
# API docs: http://localhost:8006/docs
|
||||
# Health check: http://localhost:8006/health
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Copy `.env.example` to `.env` and adjust:
|
||||
|
||||
```bash
|
||||
API_PORT=8006 # Server port
|
||||
ENABLE_RANDOM_DELAYS=true # Add realistic delays
|
||||
MIN_DELAY_MS=200 # Minimum delay
|
||||
MAX_DELAY_MS=800 # Maximum delay
|
||||
ERROR_RATE=0.0 # Error rate (0.0 to 1.0)
|
||||
DEFAULT_PAYMENT_STATUS=approved # approved, pending, rejected
|
||||
```
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Checkout Pro (Preferences)
|
||||
|
||||
```bash
|
||||
# Create payment link
|
||||
POST /v1/preferences
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"title": "Visita a domicilio",
|
||||
"quantity": 1,
|
||||
"unit_price": 95000,
|
||||
"currency_id": "ARS"
|
||||
}
|
||||
],
|
||||
"external_reference": "SR-12345",
|
||||
"back_urls": {
|
||||
"success": "https://backoffice.amarmascotas.ar/pagos/success/",
|
||||
"pending": "https://backoffice.amarmascotas.ar/pagos/pending/",
|
||||
"failure": "https://backoffice.amarmascotas.ar/pagos/failure/"
|
||||
},
|
||||
"notification_url": "https://backoffice.amarmascotas.ar/payments/mp/webhook/"
|
||||
}
|
||||
|
||||
# Get preference
|
||||
GET /v1/preferences/{preference_id}
|
||||
```
|
||||
|
||||
### Checkout API (Payments)
|
||||
|
||||
```bash
|
||||
# Create payment
|
||||
POST /v1/payments
|
||||
Headers:
|
||||
X-Idempotency-Key: unique-key-123
|
||||
Body:
|
||||
{
|
||||
"transaction_amount": 95000,
|
||||
"description": "Visita a domicilio",
|
||||
"payment_method_id": "visa",
|
||||
"payer": {
|
||||
"email": "test@example.com",
|
||||
"identification": {
|
||||
"type": "DNI",
|
||||
"number": "12345678"
|
||||
}
|
||||
},
|
||||
"application_fee": 45000
|
||||
}
|
||||
|
||||
# Get payment details
|
||||
GET /v1/payments/{payment_id}
|
||||
```
|
||||
|
||||
### OAuth
|
||||
|
||||
```bash
|
||||
# Exchange authorization code for tokens
|
||||
POST /oauth/token
|
||||
{
|
||||
"grant_type": "authorization_code",
|
||||
"client_id": "APP_ID",
|
||||
"client_secret": "APP_SECRET",
|
||||
"code": "AUTH_CODE"
|
||||
}
|
||||
|
||||
# Refresh access token
|
||||
POST /oauth/token
|
||||
{
|
||||
"grant_type": "refresh_token",
|
||||
"client_id": "APP_ID",
|
||||
"client_secret": "APP_SECRET",
|
||||
"refresh_token": "REFRESH_TOKEN"
|
||||
}
|
||||
```
|
||||
|
||||
### Mock Control
|
||||
|
||||
```bash
|
||||
# Get mock database stats
|
||||
GET /mock/stats
|
||||
|
||||
# Reset mock database
|
||||
GET /mock/reset
|
||||
|
||||
# Update mock configuration
|
||||
POST /mock/config
|
||||
{
|
||||
"default_payment_status": "approved",
|
||||
"error_rate": 0.1
|
||||
}
|
||||
|
||||
# Simulate webhook notification
|
||||
POST /mock/webhook?topic=payment&resource_id=12345
|
||||
```
|
||||
|
||||
## Response Format
|
||||
|
||||
All responses include `_mock: "MercadoPago"` to identify mock data:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 123456789,
|
||||
"status": "approved",
|
||||
"transaction_amount": 95000,
|
||||
"_mock": "MercadoPago"
|
||||
}
|
||||
```
|
||||
|
||||
## Testing Scenarios
|
||||
|
||||
### Test Payment Link Creation
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
BASE_URL = "http://localhost:8006"
|
||||
|
||||
# Create preference
|
||||
pref_resp = requests.post(f"{BASE_URL}/v1/preferences", json={
|
||||
"items": [{
|
||||
"title": "Visita a domicilio",
|
||||
"quantity": 1,
|
||||
"unit_price": 95000,
|
||||
"currency_id": "ARS"
|
||||
}],
|
||||
"external_reference": "SR-12345"
|
||||
})
|
||||
pref = pref_resp.json()
|
||||
print(f"Payment link: {pref['init_point']}")
|
||||
```
|
||||
|
||||
### Test Direct Payment with Split
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
BASE_URL = "http://localhost:8006"
|
||||
|
||||
# Create payment with application fee (split)
|
||||
payment_resp = requests.post(
|
||||
f"{BASE_URL}/v1/payments",
|
||||
headers={"X-Idempotency-Key": "unique-123"},
|
||||
json={
|
||||
"transaction_amount": 95000,
|
||||
"description": "Visita a domicilio",
|
||||
"payment_method_id": "visa",
|
||||
"payer": {
|
||||
"email": "test@example.com",
|
||||
"identification": {"type": "DNI", "number": "12345678"}
|
||||
},
|
||||
"application_fee": 45000 # Platform fee
|
||||
}
|
||||
)
|
||||
payment = payment_resp.json()
|
||||
print(f"Payment status: {payment['status']}")
|
||||
print(f"Net amount (for vet): ${payment['net_amount']}")
|
||||
```
|
||||
|
||||
### Test Different Payment Statuses
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
BASE_URL = "http://localhost:8006"
|
||||
|
||||
# Configure mock to return rejected payments
|
||||
requests.post(f"{BASE_URL}/mock/config", json={
|
||||
"default_payment_status": "rejected"
|
||||
})
|
||||
|
||||
# Now all payments will be rejected
|
||||
payment_resp = requests.post(f"{BASE_URL}/v1/payments", json={...})
|
||||
print(payment_resp.json()["status"]) # "rejected"
|
||||
|
||||
# Reset to approved
|
||||
requests.post(f"{BASE_URL}/mock/config", json={
|
||||
"default_payment_status": "approved"
|
||||
})
|
||||
```
|
||||
|
||||
### Test Error Scenarios
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
BASE_URL = "http://localhost:8006"
|
||||
|
||||
# Configure 50% error rate
|
||||
requests.post(f"{BASE_URL}/mock/config", json={
|
||||
"error_rate": 0.5
|
||||
})
|
||||
|
||||
# Half of requests will now fail with 500 error
|
||||
for i in range(10):
|
||||
try:
|
||||
resp = requests.post(f"{BASE_URL}/v1/payments", json={...})
|
||||
print(f"Request {i}: Success")
|
||||
except:
|
||||
print(f"Request {i}: Failed")
|
||||
```
|
||||
|
||||
## Data Generator
|
||||
|
||||
This vein uses the independent `datagen` tool from `ward/tools/datagen/mercadopago.py`.
|
||||
See `ward/tools/datagen/README.md` for data generation details.
|
||||
|
||||
## Integration with Amar Backend
|
||||
|
||||
Point your Amar backend to the mock MercadoPago API:
|
||||
|
||||
```python
|
||||
# settings.py or .env
|
||||
MP_PLATFORM_ACCESS_TOKEN = "mock_token" # Any value works
|
||||
MP_API_BASE_URL = "http://localhost:8006" # Point to mock
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Mock database is in-memory (resets on server restart)
|
||||
- All payment IDs are randomly generated
|
||||
- Payment status can be configured via `/mock/config`
|
||||
- Webhook notifications can be simulated via `/mock/webhook`
|
||||
- OAuth tokens are generated but not validated
|
||||
Reference in New Issue
Block a user