Add webhook endpoints to receive events from Odoo (sale orders, stock picking, invoices) and send WhatsApp notifications when orders are confirmed, shipped, or payments are received. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
151 lines
4.0 KiB
Python
151 lines
4.0 KiB
Python
from fastapi import APIRouter, HTTPException, Header, Request
|
|
from pydantic import BaseModel
|
|
from typing import Optional, Dict, Any
|
|
import httpx
|
|
import hmac
|
|
import hashlib
|
|
|
|
from app.config import get_settings
|
|
|
|
router = APIRouter(prefix="/api/webhooks", tags=["webhooks"])
|
|
settings = get_settings()
|
|
|
|
|
|
class OdooWebhookPayload(BaseModel):
|
|
model: str
|
|
action: str
|
|
record_id: int
|
|
values: Dict[str, Any] = {}
|
|
old_values: Dict[str, Any] = {}
|
|
|
|
|
|
@router.post("/odoo")
|
|
async def handle_odoo_webhook(payload: OdooWebhookPayload):
|
|
"""
|
|
Handle webhooks from Odoo.
|
|
Odoo sends events when records are created/updated/deleted.
|
|
"""
|
|
handlers = {
|
|
"sale.order": handle_sale_order_event,
|
|
"stock.picking": handle_stock_picking_event,
|
|
"account.move": handle_invoice_event,
|
|
}
|
|
|
|
handler = handlers.get(payload.model)
|
|
if handler:
|
|
await handler(payload)
|
|
|
|
return {"status": "received"}
|
|
|
|
|
|
async def handle_sale_order_event(payload: OdooWebhookPayload):
|
|
"""Handle sale order events"""
|
|
if payload.action != "write":
|
|
return
|
|
|
|
old_state = payload.old_values.get("state")
|
|
new_state = payload.values.get("state")
|
|
|
|
# Order confirmed
|
|
if old_state == "draft" and new_state == "sale":
|
|
await send_order_confirmation(payload.record_id)
|
|
|
|
# Order delivered
|
|
elif new_state == "done":
|
|
await send_order_delivered(payload.record_id)
|
|
|
|
|
|
async def handle_stock_picking_event(payload: OdooWebhookPayload):
|
|
"""Handle stock picking (delivery) events"""
|
|
if payload.action != "write":
|
|
return
|
|
|
|
new_state = payload.values.get("state")
|
|
|
|
# Shipment sent
|
|
if new_state == "done":
|
|
await send_shipment_notification(payload.record_id)
|
|
|
|
|
|
async def handle_invoice_event(payload: OdooWebhookPayload):
|
|
"""Handle invoice events"""
|
|
if payload.action != "write":
|
|
return
|
|
|
|
# Payment received
|
|
if payload.values.get("payment_state") == "paid":
|
|
await send_payment_confirmation(payload.record_id)
|
|
|
|
|
|
async def send_order_confirmation(order_id: int):
|
|
"""Send WhatsApp message for order confirmation"""
|
|
try:
|
|
async with httpx.AsyncClient() as client:
|
|
# Get order details
|
|
response = await client.get(
|
|
f"{settings.API_GATEWAY_URL}/api/odoo/sales/{order_id}",
|
|
timeout=10,
|
|
)
|
|
if response.status_code != 200:
|
|
return
|
|
|
|
order = response.json()
|
|
|
|
# Get partner details
|
|
partner_response = await client.get(
|
|
f"{settings.API_GATEWAY_URL}/api/odoo/partners/{order['partner_id']}",
|
|
timeout=10,
|
|
)
|
|
if partner_response.status_code != 200:
|
|
return
|
|
|
|
partner = partner_response.json()
|
|
phone = partner.get("mobile") or partner.get("phone")
|
|
|
|
if not phone:
|
|
return
|
|
|
|
# Format message
|
|
message = f"""*Pedido Confirmado*
|
|
|
|
Hola {partner.get('name', '')},
|
|
|
|
Tu pedido *{order['name']}* ha sido confirmado.
|
|
|
|
Total: {order['currency']} {order['amount_total']:.2f}
|
|
|
|
Gracias por tu compra."""
|
|
|
|
# Send via API Gateway
|
|
await client.post(
|
|
f"{settings.API_GATEWAY_URL}/api/internal/send-by-phone",
|
|
json={"phone": phone, "message": message},
|
|
timeout=10,
|
|
)
|
|
except Exception as e:
|
|
print(f"Failed to send order confirmation: {e}")
|
|
|
|
|
|
async def send_shipment_notification(picking_id: int):
|
|
"""Send WhatsApp message for shipment"""
|
|
# Similar implementation - get picking details and send notification
|
|
pass
|
|
|
|
|
|
async def send_order_delivered(order_id: int):
|
|
"""Send WhatsApp message for delivered order"""
|
|
# Similar implementation
|
|
pass
|
|
|
|
|
|
async def send_payment_confirmation(invoice_id: int):
|
|
"""Send WhatsApp message for payment received"""
|
|
# Similar implementation
|
|
pass
|
|
|
|
|
|
@router.get("/odoo/test")
|
|
async def test_webhook():
|
|
"""Test endpoint for webhook connectivity"""
|
|
return {"status": "ok", "service": "webhooks"}
|