Skip to content

BSS Payment QR Code & Event Flow Specification

Purpose: Define the payment QR code structure and event persistence flow between ABS and Odoo.

Key Principle: ABS is the source of truth for service and payment event history. Odoo consumes events to enrich CRM customer experience.


Payment QR Code Structure

Purpose

When quota is exhausted during battery swap, the attendant app displays a payment QR code that contains both Service Event and Payment Event data. This enables Odoo to: 1. Process payment (retail checkout function) 2. Update CRM records with service history 3. Provide transparency to customer

QR Code JSON Payload

{
  "qr_type": "abs_payment_request",
  "version": "1.0",

  "service_event": {
    "event_id": "SE-12345",
    "event_type": "BATTERY_SWAP",
    "timestamp": "2025-01-15T10:25:00Z",
    "plan_id": "bss-plan-weekly-freedom-nairobi-v2-plan1",
    "customer_id": "CUST-001",
    "attendant_id": "ATT-001",
    "station_id": "STATION_XYZ",

    "batteries": {
      "returned": {
        "id": "BAT-12345",
        "kwh": 4.8
      },
      "issued": {
        "id": "BAT-67890",
        "kwh": 30.4
      },
      "net_kwh_delivered": 25.6
    },

    "quota_consumption": {
      "swap_count": 1,
      "electricity_kwh": 25.6
    }
  },

  "payment_event": {
    "event_id": "PE-78910",
    "event_type": "TOPUP_PAYMENT",
    "timestamp": "2025-01-15T10:25:00Z",
    "amount": 15.00,
    "currency": "USD",
    "merchant_station": "STATION_XYZ",
    "service_description": "Battery Swap + Electricity Top-up",
    "quota_deficit_kwh": 15.6,
    "linked_service_event_id": "SE-12345"
  },

  "abs_metadata": {
    "abs_version": "2.0.0",
    "correlation_id": "TXN-12345",
    "callback_url": "mqtt://abs-platform/payment/confirm/TXN-12345"
  }
}

Field Descriptions

Service Event

Field Type Description
event_id string Unique service event ID (ABS-generated)
event_type string Type of service (BATTERY_SWAP, FIRST_ISSUANCE, etc.)
timestamp ISO 8601 Event creation timestamp
plan_id string ServicePlan ID
customer_id string Customer ID
attendant_id string Attendant who performed service
station_id string Station/location ID
batteries.returned object Incoming battery details (null for first visit)
batteries.issued object Outgoing battery details
batteries.net_kwh_delivered number Net electricity delivered (outgoing - incoming)
quota_consumption.swap_count number Number of swaps consumed (typically 1)
quota_consumption.electricity_kwh number Electricity quota consumed

Payment Event

Field Type Description
event_id string Unique payment event ID (ABS-generated)
event_type string Type of payment (TOPUP_PAYMENT, RENEWAL_PAYMENT, etc.)
timestamp ISO 8601 Event creation timestamp
amount number Payment amount
currency string Currency code (USD, KES, etc.)
merchant_station string Station/merchant ID
service_description string Human-readable description
quota_deficit_kwh number Amount of quota deficit being paid for
linked_service_event_id string Reference to associated service event

ABS Metadata

Field Type Description
abs_version string ABS platform version
correlation_id string Transaction correlation ID for tracking
callback_url string MQTT topic for payment confirmation callback

Payment Workflow

Step-by-Step Flow

┌─────────────┐      ┌─────────────┐      ┌─────────────┐      ┌─────────────┐
│  Attendant  │      │  ABS Agent  │      │    Odoo     │      │   Rider     │
│     App     │      │  (BSS v2)   │      │     ERP     │      │     App     │
└──────┬──────┘      └──────┬──────┘      └──────┬──────┘      └──────┬──────┘
       │                    │                     │                     │
       │ 1. Scan outgoing   │                     │                     │
       │    battery         │                     │                     │
       ├───────────────────>│                     │                     │
       │                    │                     │                     │
       │                    │ 2. Calculate quota  │                     │
       │                    │    (remaining < net)│                     │
       │                    │                     │                     │
       │ 3. QUOTA_EXHAUSTED │                     │                     │
       │    + QR code data  │                     │                     │
       │<───────────────────┤                     │                     │
       │                    │                     │                     │
       │ 4. Display QR code │                     │                     │
       │    on screen       │                     │                     │
       │                    │                     │                     │
       │                    │                     │  5. Scan QR         │
       │                    │                     │<────────────────────┤
       │                    │                     │                     │
       │                    │                     │  6. Payment page    │
       │                    │                     │    (pre-filled)     │
       │                    │                     │────────────────────>│
       │                    │                     │                     │
       │                    │                     │  7. Complete payment│
       │                    │                     │<────────────────────┤
       │                    │                     │                     │
       │                    │                     │ 8. Update CRM       │
       │                    │                     │    (from events)    │
       │                    │                     │                     │
       │                    │ 9. Payment confirm  │                     │
       │                    │    (MQTT callback)  │                     │
       │                    │<────────────────────┤                     │
       │                    │                     │                     │
       │ 10. Payment received                     │                     │
       │     notification   │                     │                     │
       │<───────────────────┤                     │                     │
       │                    │                     │                     │
       │ 11. Hand battery   │                     │                     │
       │     to rider       │                     │                     │
       │───────────────────────────────────────────────────────────────>│
       │                    │                     │                     │
       │ 12. Service Complete                     │                     │
       ├───────────────────>│                     │                     │
       │                    │                     │                     │
       │                    │ 13. Persist events  │                     │
       │                    │     to ABS DB       │                     │
       │                    │                     │                     │
       │                    │ 14. Update quotas   │                     │
       │                    │     & FSM states    │                     │
       │                    │                     │                     │
       │ 15. Receipt        │                     │                     │
       │<───────────────────┤                     │                     │
       │                    │                     │                     │

Detailed Steps

Step Actor Action Data Flow
1 Attendant Scans outgoing battery barcode → ABS Agent
2 ABS Agent Calculates quota: remaining_quota < net_kwh Internal
3 ABS Agent Generates Service Event + Payment Event, returns QR data → Attendant App
4 Attendant App Displays QR code on screen Visual
5 Rider Scans QR code with rider app → Odoo
6 Odoo Opens payment page with pre-filled data from events → Rider
7 Rider Completes payment (mobile money, card, etc.) → Odoo
8 Odoo Updates CRM with service event history Internal (Odoo)
9 Odoo Sends payment confirmation via MQTT → ABS Agent
10 ABS Agent Notifies attendant app of payment receipt → Attendant App
11 Attendant Hands charged battery to rider Physical
12 Attendant Clicks "Service Complete" → ABS Agent
13 ABS Agent Persists Service Event + Payment Event to ABS database → Database
14 ABS Agent Updates quota consumption, FSM states → ServicePlan
15 ABS Agent Generates receipt with event history → Attendant App

Event Persistence

ABS Database Schema (Conceptual)

Service Events Table

CREATE TABLE service_events (
  event_id VARCHAR PRIMARY KEY,
  event_type VARCHAR NOT NULL,
  timestamp TIMESTAMP NOT NULL,
  plan_id VARCHAR NOT NULL REFERENCES service_plans(id),
  customer_id VARCHAR NOT NULL,
  attendant_id VARCHAR,
  station_id VARCHAR,
  battery_returned_id VARCHAR,
  battery_returned_kwh DECIMAL(10,1),
  battery_issued_id VARCHAR,
  battery_issued_kwh DECIMAL(10,1),
  net_kwh_delivered DECIMAL(10,1),
  swap_count_consumed INT,
  electricity_kwh_consumed DECIMAL(10,1),
  created_at TIMESTAMP DEFAULT NOW()
);

Payment Events Table

CREATE TABLE payment_events (
  event_id VARCHAR PRIMARY KEY,
  event_type VARCHAR NOT NULL,
  timestamp TIMESTAMP NOT NULL,
  plan_id VARCHAR NOT NULL REFERENCES service_plans(id),
  customer_id VARCHAR NOT NULL,
  amount DECIMAL(10,2),
  currency VARCHAR(3),
  merchant_station VARCHAR,
  service_description TEXT,
  quota_deficit_kwh DECIMAL(10,1),
  linked_service_event_id VARCHAR REFERENCES service_events(event_id),
  odoo_receipt_id VARCHAR,
  payment_method VARCHAR,
  created_at TIMESTAMP DEFAULT NOW()
);

Event Lifecycle

┌────────────────────────────────────────────────────────────┐
│                    Event Lifecycle                          │
└────────────────────────────────────────────────────────────┘

1. EVENT CREATION (when quota exhausted)
   ├─ ABS Agent creates Service Event
   ├─ ABS Agent creates Payment Event
   └─ Events encoded in QR code

2. EVENT IN-FLIGHT (during payment)
   ├─ Events travel via QR code to Odoo
   ├─ Odoo uses events to populate payment page
   └─ Odoo updates CRM customer history

3. EVENT CONFIRMATION (payment received)
   ├─ Odoo sends payment confirmation to ABS
   ├─ ABS Agent updates Payment Event with Odoo receipt ID
   └─ Attendant app notified

4. EVENT PERSISTENCE (service complete)
   ├─ ABS Agent persists Service Event to database
   ├─ ABS Agent persists Payment Event to database
   ├─ ServicePlan quotas updated
   └─ FSM states transitioned

5. EVENT HISTORY (transparency)
   ├─ ABS provides event history API
   ├─ Odoo can query event history for CRM
   └─ Customer can view event history via app

ABS ↔ Odoo Integration Contract

Data Ownership

Data Type Owner Consumer Purpose
Service Events ABS Odoo Service history, customer transparency
Payment Events ABS Odoo Payment history, reconciliation
Payment Processing Odoo ABS Payment confirmation, receipt ID
Customer CRM Odoo ABS Customer details, subscription status
ServicePlan State ABS Odoo Quota status, service availability

API Contracts

1. ABS → Odoo: Payment Request (via QR Code)

Method: QR code scan
Data: Service Event + Payment Event (JSON)
Purpose: Initiate payment, provide context

2. Odoo → ABS: Payment Confirmation (MQTT)

Topic: mqtt://abs-platform/payment/confirm/{correlation_id}
Payload:

{
  "correlation_id": "TXN-12345",
  "payment_event_id": "PE-78910",
  "odoo_receipt_id": "PAY-78910",
  "payment_status": "SUCCESS",
  "payment_method": "MOBILE_MONEY",
  "payment_timestamp": "2025-01-15T10:24:30Z"
}

3. ABS → Odoo: Event History Query (GraphQL/REST)

Endpoint: GET /api/v1/service-events?customer_id={id}&limit=10
Response:

{
  "service_events": [ /* array of service events */ ],
  "payment_events": [ /* array of payment events */ ],
  "total_count": 25,
  "page": 1
}


Error Handling

Payment Timeout

Scenario: Rider scans QR but doesn't complete payment within 5 minutes.

Flow: 1. Attendant app displays "Payment Timeout" 2. Attendant can retry (generate new QR) or cancel service 3. If retry: New correlation_id generated, new QR displayed 4. Original events are not persisted until payment confirmed

Payment Failure

Scenario: Payment declined by payment processor.

Flow: 1. Odoo sends payment failure notification to ABS 2. ABS Agent notifies attendant app 3. Attendant app displays "Payment Declined - Retry?" 4. If retry: Same QR can be re-scanned, or new payment method attempted 5. Events not persisted until successful payment

Duplicate Payment

Scenario: Rider accidentally pays twice for same service.

Flow: 1. ABS checks correlation_id + payment_event_id uniqueness 2. If duplicate detected: Ignore second payment, flag for refund 3. Odoo CRM flags duplicate payment for manual resolution 4. Only one Payment Event persisted per Service Event


Receipt Generation

Receipt Content

The receipt combines Service Event + Payment Event data:

════════════════════════════════════════════
      BATTERY SWAP SERVICE RECEIPT
════════════════════════════════════════════
Transaction ID: TXN-12345
Date/Time: 2025-01-15 10:30:00

Customer: John Doe (CUST-001)
Plan: Weekly Freedom Nairobi - Basic

────────────────────────────────────────────
SERVICE DETAILS
────────────────────────────────────────────
Battery Returned:  BAT-12345 (4.8 kWh)
Battery Issued:    BAT-67890 (30.4 kWh)
Net Electricity:   25.6 kWh

────────────────────────────────────────────
QUOTA CONSUMPTION
────────────────────────────────────────────
Swap Count:        1 swap
Electricity:       25.6 kWh

────────────────────────────────────────────
QUOTA REMAINING
────────────────────────────────────────────
Swap Count:        3 of 10 swaps
Electricity:       29.9 of 400 kWh

────────────────────────────────────────────
PAYMENT
────────────────────────────────────────────
Amount Paid:       $15.00 USD
Method:            Mobile Money
Receipt ID:        PAY-78910
Timestamp:         2025-01-15 10:24:30

────────────────────────────────────────────
Service provided by: Station XYZ
Attendant: ATT-001

Thank you for using our service!
════════════════════════════════════════════

Implementation Checklist

Phase 1: QR Code Generation

  • [ ] Implement Service Event creation logic
  • [ ] Implement Payment Event creation logic
  • [ ] Create QR code encoding function (JSON → QR)
  • [ ] Add QR code display to attendant app UI
  • [ ] Test QR code size (ensure scannable)

Phase 2: Odoo Integration

  • [ ] Configure Odoo QR code scanner
  • [ ] Implement JSON parsing in Odoo
  • [ ] Create payment page pre-fill logic
  • [ ] Implement CRM update from events
  • [ ] Configure MQTT payment confirmation callback

Phase 3: Event Persistence

  • [ ] Create service_events database table
  • [ ] Create payment_events database table
  • [ ] Implement event persistence functions
  • [ ] Add foreign key constraints
  • [ ] Create event history API endpoints

Phase 4: Testing

  • [ ] Unit tests: Event creation, QR encoding
  • [ ] Integration tests: QR scan → Payment → Confirmation
  • [ ] Error scenarios: Timeout, failure, duplicate
  • [ ] Load testing: Multiple simultaneous payments
  • [ ] E2E testing: Complete workflow validation

Conclusion

This design ensures: 1. ABS as source of truth - All events persisted in ABS database 2. Odoo as payment processor - Handles retail checkout, CRM updates 3. Transparency - Event history available to all stakeholders 4. Auditability - Complete event trail from service to payment 5. Simplicity - QR code carries all necessary context

Next Steps: Proceed with implementation according to checklist above.