BSS-Odoo Billing Synchronization Workflow¶
Workflow Diagram¶

Complete sequence diagram showing the three billing synchronization phases: Phase 1 (Product Synchronization from ABS to Odoo), Phase 2 (Subscription Lifecycle from Odoo to ABS), and Phase 3 (Payment Synchronization), including payment overdue and usage-based billing scenarios.
Overview¶
This workflow defines the billing synchronization pattern between ABS ServicePlan lifecycle and Odoo subscription billing operations. Following DIRAC Framework principles, ABS handles service delivery while Odoo manages all billing and customer sales interactions.
Core Principles¶
Federation-Based Integration¶
- ABS: Service definition, execution, FSM state management
- Odoo: Billing operations, pricing, customer sales, subscription management
- FED Layer: Mediates data translation and synchronization (via MQTT)
- No Schema Pollution: Odoo integration data confined to BSS agent_state
Billing Responsibility Separation¶
- ABS Does NOT: Generate invoices, process payments, manage customer billing
- ABS DOES: Sync payment-cycle FSM states with Odoo billing signals
- Odoo Leads: All billing decisions, payment processing, subscription lifecycle
- ABS Follows: Updates internal FSM states based on Odoo billing events
Workflow Phases¶
Phase 1: Product Synchronization (ABS → Odoo)¶
ABS ServicePlanTemplate → Odoo Product Template¶
ABS Event: ServicePlanTemplate Created
↓ MQTT: emit/abs/product_template/{template_id}/created
↓ FED Layer Translation
↓ Odoo: Create Product Template
↓ Store: template_id as product.default_code
Key Mappings:
- template_id → product.default_code (linking mechanism)
- name → product.name
- billing_currency → product.currency_id
- CommonTerms.monthly_fee → product.list_price
Phase 2: Subscription Lifecycle (Odoo → ABS)¶
Customer Signs Up in Odoo¶
Odoo Event: Customer creates subscription
↓ MQTT: emit/odoo/subscription/{subscription_id}/created
↓ ABS MQTT Listener
↓ BSS Agent: createServicePlanFromOdoo()
↓ ServicePlan created with odoo_subscription_id link
ServicePlan Creation Pattern:
// BSS Agent receives Odoo subscription creation
const servicePlan = {
customer_id: payload.partner_id,
template_id: payload.template_id, // ABS template reference
plan_state: {
status: 'ACTIVE',
agent_state: {
// Odoo integration data (domain isolation)
odoo_subscription_id: payload.subscription_id,
odoo_subscription_state: payload.state,
odoo_last_sync_at: timestamp
}
},
service_state: 'WAIT_BATTERY_ISSUE', // ABS FSM state
payment_state: 'CURRENT' // Derived from Odoo
};
Phase 3: Payment Synchronization (Odoo → ABS)¶
Odoo Billing Events → ABS FSM Updates¶
Odoo Event: Invoice created/Payment processed
↓ MQTT: emit/odoo/subscription/{subscription_id}/payment_updated
↓ ABS MQTT Listener
↓ BSS Agent: syncOdooSubscription()
↓ Update payment_state FSM
↓ Emit FSM signals if needed
BSS Agent Integration Points¶
serviceAgent.syncOdooSubscription()¶
Purpose: Synchronize ABS payment-cycle FSM with Odoo billing events
Input Pattern:
{
action: 'SYNC_ODOO_SUBSCRIPTION',
odoo_payload: {
subscription_id: 12345,
payment_state: 'paid', // Odoo payment status
subscription_state: 'in_progress', // Odoo subscription status
invoice_id: 'INV-001',
payment_date: '2025-01-15T14:30:00Z'
}
}
Agent Logic Flow:
1. Validate odoo_subscription_id matches agent_state
2. Map Odoo payment_state to ABS payment FSM
3. Update agent_state with Odoo sync data
4. Generate FSM inputs if state transition needed
5. Return signals for orchestrator
State Mapping Table:
| Odoo Payment State | ABS Payment FSM | FSM Input Generated |
|-------------------|-----------------|-------------------|
| not_paid | RENEWAL_DUE | SUBSCRIPTION_EXPIRED |
| paid | CURRENT | RENEWAL_PAID |
| partial | RENEWAL_DUE | (no change) |
| overdue | RENEWAL_DUE | QUOTA_EXHAUSTED |
serviceAgent.checkOdooPaymentStatus()¶
Purpose: Query current payment status for service availability decisions
Validator Array Pattern:
const paymentValidators = [
{
check: () => agent_state.odoo_payment_state === 'paid',
signal: 'PAYMENT_CURRENT'
},
{
check: () => agent_state.odoo_subscription_state === 'to_renew',
signal: 'RENEWAL_REQUIRED'
},
{
check: () => !agent_state.odoo_subscription_id,
signal: 'ODOO_SYNC_ERROR'
}
];
serviceAgent.reportServiceUsageToOdoo()¶
Purpose: Report ABS service milestones to trigger Odoo billing
Usage Events: - Battery swap completion → Trigger usage-based billing - Service quota exhaustion → Request quota top-up billing - Service termination → Final settlement billing
MQTT Pattern:
ABS Event: Battery swap completed
↓ BSS Agent: reportServiceUsageToOdoo()
↓ MQTT: emit/abs/service_usage/{plan_id}/battery_swap_completed
↓ Odoo: Create milestone invoice
↓ MQTT: emit/odoo/subscription/{subscription_id}/invoice_created
↓ ABS: Sync billing status
MQTT Topic Patterns¶
ABS → Odoo (Service Events)¶
emit/abs/product_template/{template_id}/createdemit/abs/service_usage/{plan_id}/battery_swap_completedemit/abs/service_usage/{plan_id}/service_terminated
Odoo → ABS (Billing Events)¶
emit/odoo/subscription/{subscription_id}/createdemit/odoo/subscription/{subscription_id}/payment_updatedemit/odoo/subscription/{subscription_id}/state_changedemit/odoo/subscription/{subscription_id}/invoice_created
Data Flow Examples¶
Example 1: Monthly Renewal¶
Day 1: Odoo creates monthly invoice
↓ emit/odoo/subscription/123/invoice_created
↓ ABS: No action (invoice creation doesn't affect service)
Day 30: Customer pays invoice
↓ emit/odoo/subscription/123/payment_updated
↓ ABS: syncOdooSubscription()
↓ payment_state: CURRENT
↓ Service remains available
Day 35: Payment overdue
↓ emit/odoo/subscription/123/payment_updated (overdue)
↓ ABS: syncOdooSubscription()
↓ payment_state: RENEWAL_DUE
↓ FSM: SUBSCRIPTION_EXPIRED
↓ Service access blocked until payment
Example 2: Usage-Based Billing¶
Customer: Completes battery swap
↓ ABS: Service milestone completed
↓ emit/abs/service_usage/plan-123/battery_swap_completed
↓ Odoo: Creates usage invoice
↓ emit/odoo/subscription/123/invoice_created
↓ ABS: Logs billing event (no state change)
Later: Customer pays usage invoice
↓ emit/odoo/subscription/123/payment_updated
↓ ABS: Confirms payment received (service continues)
Implementation Guidelines¶
Agent State Structure¶
interface BSSAgentState {
// Core agent state
agent_version: string;
swaps_today: number;
execution_count: number;
// Odoo integration (domain isolation)
odoo_subscription_id: number | null;
odoo_payment_state: string | null;
odoo_subscription_state: string | null;
odoo_last_sync_at: string | null;
odoo_payment_method: string | null;
odoo_currency_id: string | null;
}
Error Handling Pattern¶
const syncValidators = [
{
check: () => !request.odoo_payload?.subscription_id,
signal: 'ODOO_SYNC_ERROR',
metadata: { reason: 'Missing subscription_id' }
},
{
check: () => agent_state.odoo_subscription_id !== request.odoo_payload.subscription_id,
signal: 'ODOO_SYNC_ERROR',
metadata: { reason: 'Subscription ID mismatch' }
}
];
Integration Testing Points¶
- Product sync: ServicePlanTemplate → Odoo Product creation
- Subscription creation: Odoo subscription → ABS ServicePlan
- Payment updates: Odoo payment events → ABS FSM transitions
- Service milestones: ABS events → Odoo usage billing
- Error scenarios: Network failures, mismatched IDs, invalid states
Benefits¶
Clean Separation¶
- ABS: Focuses on service delivery and FSM management
- Odoo: Handles all customer-facing billing complexity
- No billing logic in ABS - pure service orchestration
Federation Compliance¶
- Zero Odoo customization required
- Minimal ABS changes - only agent_state fields
- FED layer mediation via MQTT messaging
Scalability¶
- Event-driven architecture supports async processing
- Domain isolation prevents billing concerns from polluting service logic
- Standard patterns applicable to other DIRAC services (FCS, EMS)
This workflow ensures ABS remains focused on service delivery while leveraging Odoo's robust billing capabilities through clean, federated integration patterns.